cancel
Showing results for 
Search instead for 
Did you mean: 

Error: "Horizon isn't installed, or you're running an incompatible of home/horizon"

Anonymous
Not applicable

I've almost completed what I think is a pretty solid script to allow the user to download DLC (assetbundle) for my app using Oculus Platform. All goes well from entitlement checks, to retrieving prices, to checking already purchased items, to the purchase itself. 

Starting the actual download however fails and returns this error:

Either the service couldn't be connected to, Horizon isn't installed, or you're running an incompatible of home/horizon

What's strange is that I can't find anything about this error. Literally zero results on google.

  • I'm testing the app and it's IAP with test users, which should be fine
  • This error occurs in the build (I have a worldspace canvas showing debug info). Because there's such little information on this error, I think it's because the error comes from the Quest itself and not from any script of my project (and therefore hard to spot).
  • It occurs both when I've installed the apk directly to my Quest 2 and after downloading it from App Lab
  • GPT suggests it has likely something to do with a server or software problem on Oculus' side. However, I just don't buy it since it's a fresh new script and therefore more at risk of being buggy than Oculus. 
  • You can't just simply install Horizon as an app, so I installed Horizon Workrooms. Of course didn't solve anything.
1 ACCEPTED SOLUTION

Accepted Solutions

Anonymous
Not applicable

Thanks for replying, I fixed it but forgot that I reported this problem.

My approach around handling AssetIDs was wrong. They're susceptible to change and can't just be stored somewhere. I believe that this error happens when you try to download an AssetID that doesn't exist. Or it does exist but belongs to another app (hence why the specific 'horizon isn't installed' error is so rare).

Anyway, we got it fixed by always relying on GetList() at the start of the app. Here's a snippet of our approach:

void OnPurchasesRetrieved()
{
    Debug.Log("Finished checking purchased DLC. Retrieving downloadable assets");
    GetOculusAssetFileList();
}

public void GetOculusAssetFileList()
{
    AssetFile.GetList().OnComplete((Message<AssetDetailsList> msg) =>
    {
        if (msg.IsError)
        {
            Debug.LogError("Error retrieving DLC information: " + msg.GetError().Message);
            loadStatus.text = "Error retrieving DLC information";
            return;
        }

        List<ulong> assetIds = new List<ulong>();
        Dictionary<string, string> newSkuToFilepathMap = new Dictionary<string, string>();

        FetchPurchasedProducts((purchasedSkus) =>
        {
            foreach (var assetDetail in msg.Data)
            {
                Debug.Log($"AssetID: {assetDetail.AssetId}, Filepath: {assetDetail.Filepath}");
                if (!string.IsNullOrEmpty(assetDetail.Filepath))
                {
                    var filepathParts = assetDetail.Filepath.Split('/');
                    var filename = filepathParts.LastOrDefault();
                    var sku = Path.GetFileNameWithoutExtension(filename);

                    if (thumbnailSKUs.Contains(sku))
                    {
                        newSkuToFilepathMap[sku] = assetDetail.Filepath;
                        bool isDownloaded = File.Exists(assetDetail.Filepath);
                        skuDownloadStatus[sku] = isDownloaded;
                        assetIds.Add(assetDetail.AssetId);
                        skuToAssetIdMap[sku] = assetDetail.AssetId;
                        skuPurchaseStatus[sku] = purchasedSkus.Contains(sku);
                    }
                }
            }
            skuToFilepathMap = newSkuToFilepathMap;
            dlcAssetIds = assetIds.ToArray();
        });
    });
}

private void FetchPurchasedProducts(Action<List<string>> onComplete)
{
    IAP.GetViewerPurchases().OnComplete((Message<PurchaseList> msg) =>
    {
        if (msg.IsError)
        {
            Debug.LogError("Error checking purchased DLC: " + msg.GetError().Message);
            onComplete(new List<string>());
            return;
        }

        List<string> purchasedSkus = msg.Data.Select(p => p.Sku).ToList();
        onComplete(purchasedSkus);
    });
}

 

View solution in original post

2 REPLIES 2

SwordmasterJR
Honored Guest

Hi there,

Any update on this? We're having the exact same problem.

Anonymous
Not applicable

Thanks for replying, I fixed it but forgot that I reported this problem.

My approach around handling AssetIDs was wrong. They're susceptible to change and can't just be stored somewhere. I believe that this error happens when you try to download an AssetID that doesn't exist. Or it does exist but belongs to another app (hence why the specific 'horizon isn't installed' error is so rare).

Anyway, we got it fixed by always relying on GetList() at the start of the app. Here's a snippet of our approach:

void OnPurchasesRetrieved()
{
    Debug.Log("Finished checking purchased DLC. Retrieving downloadable assets");
    GetOculusAssetFileList();
}

public void GetOculusAssetFileList()
{
    AssetFile.GetList().OnComplete((Message<AssetDetailsList> msg) =>
    {
        if (msg.IsError)
        {
            Debug.LogError("Error retrieving DLC information: " + msg.GetError().Message);
            loadStatus.text = "Error retrieving DLC information";
            return;
        }

        List<ulong> assetIds = new List<ulong>();
        Dictionary<string, string> newSkuToFilepathMap = new Dictionary<string, string>();

        FetchPurchasedProducts((purchasedSkus) =>
        {
            foreach (var assetDetail in msg.Data)
            {
                Debug.Log($"AssetID: {assetDetail.AssetId}, Filepath: {assetDetail.Filepath}");
                if (!string.IsNullOrEmpty(assetDetail.Filepath))
                {
                    var filepathParts = assetDetail.Filepath.Split('/');
                    var filename = filepathParts.LastOrDefault();
                    var sku = Path.GetFileNameWithoutExtension(filename);

                    if (thumbnailSKUs.Contains(sku))
                    {
                        newSkuToFilepathMap[sku] = assetDetail.Filepath;
                        bool isDownloaded = File.Exists(assetDetail.Filepath);
                        skuDownloadStatus[sku] = isDownloaded;
                        assetIds.Add(assetDetail.AssetId);
                        skuToAssetIdMap[sku] = assetDetail.AssetId;
                        skuPurchaseStatus[sku] = purchasedSkus.Contains(sku);
                    }
                }
            }
            skuToFilepathMap = newSkuToFilepathMap;
            dlcAssetIds = assetIds.ToArray();
        });
    });
}

private void FetchPurchasedProducts(Action<List<string>> onComplete)
{
    IAP.GetViewerPurchases().OnComplete((Message<PurchaseList> msg) =>
    {
        if (msg.IsError)
        {
            Debug.LogError("Error checking purchased DLC: " + msg.GetError().Message);
            onComplete(new List<string>());
            return;
        }

        List<string> purchasedSkus = msg.Data.Select(p => p.Sku).ToList();
        onComplete(purchasedSkus);
    });
}