Search Unity

UnityWebRequest has no Error following CRC Mismatch

Discussion in 'Asset Bundles' started by TitanUnity, Nov 14, 2018.

  1. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    180
    Hi,

    We recently implemented CRC values instead of Version numbers for our AssetBundle versioning. The system is working ok so far but we're having a problem capturing and displaying CRC mismatch errors when they occur.

    Take this simple example below. Assume the passed in CRC value is incorrect. What we're finding is that the 'test' UnityWebRequest object contains no errors following a CRC mismatch. Specifically none of the Debug.LogError statements fire if a mismatch occurs in the code below:

    Code (CSharp):
    1. UnityWebRequest test = UnityWebRequestAssetBundle.GetAssetBundle("http://www.oursite.com/bundle.unity3d",123456789);
    2. yield return test.SendWebRequest();
    3.  
    4. if(!test.isDone)
    5. {
    6.     Debug.LogError("LOAD NOT DONE");
    7. }
    8.  
    9. if (test.error != null)
    10. {
    11.     Debug.LogError("ERROR");
    12. }
    13.  
    14. if (test.isHttpError)
    15. {
    16.     Debug.LogError("HTTP ERROR");
    17. }
    18.  
    19. if (test.isNetworkError)
    20. {
    21.     Debug.LogError("NETWORK ERROR");
    22. }
    23.  
    The weird part is that we do find an error in our console like this:
    CRC_ERROR.JPG

    But it seems like the error originates from somewhere else. Ultimately, all I'm trying to do is capture mismatches when they occur so our team can easily find and fix them. Any help here would be great!
     
  2. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Are you loading asset bundle later?
    I suspect this error is printed when you do DownloadHandlerAssetBundle.GetContent() or acceess assetBundle property. It should return null in both cases.
     
  3. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    180
    Actually in the example above, we are not calling DownloadHandlerAssetBundle.GetContent(). I can generate a mismatch error above without attempting to get content or access the AssetBundle.

    In normal conditions calling GetContent() would be the next step to take, but I specifically created this simple example to illustrate the point that it seems the error gets thrown from another source.
     
  4. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    You are right. Looking at the code we are detecting AssetBundle load failure and print the error, however we don't report error back to UnityWebRequest because old implementation considered only network errors as errors.
    I think the request should fail. Could you report a bug for this?

    Note that I don't think we are going to backport the fix anywhere, so for now you should check UWR for error and returned bundle for null. No error in UWR and null bundle would mean the download (of bytes) was successful, but bundle could not be loaded for some reason.
     
  5. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    180
    I double confirmed this to be true. I've add a break after this code to ensure nothing else fires and I've determined specifically that it only requires these 2 lines to trigger cause the error in the console but I'm not sure how to capture the error to handle it.

    Code (CSharp):
    1. UnityWebRequest test = UnityWebRequestAssetBundle.GetAssetBundle("http://www.oursite.com/bundle.unity3d",123456789);
    2. yield return test.SendWebRequest();
     
  6. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    180
    Ah ok thank you, you posted just as I was typing my last message!
    Submitting bug report now.
     
  7. TitanUnity

    TitanUnity

    Joined:
    May 15, 2014
    Posts:
    180
  8. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
  9. dean0

    dean0

    Joined:
    Mar 7, 2014
    Posts:
    10
    Yes, this is pretty annoying, since apparently merely checking the assetbundle reference causes it to be "loaded", and will cause an error if you try to load it later unless you Unload.

    Thanks for reporting, @TitanUnity
     
  10. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    have you actually tested this code - warnings about the old system (WWW.LoadFromCacheOrDownload) encouraged me to overhaul my assetBundle loading, but after many hours of debugging, and constant crashing to desktop, I eventually just copied the example code directly into a new script and added it to a gameObject in an empty scene in a new project.. Even the raw test code causes an immediate fatal crash to desktop (Unity 2018.3.6f1);

    void Start()
    {
    StartCoroutine(GetText());
    }

    IEnumerator GetText()
    {
    using (UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle("http://www.my-server.com/mybundle"))
    {
    yield return uwr.SendWebRequest();

    if (uwr.isNetworkError || uwr.isHttpError)
    {
    Debug.Log(uwr.error);
    }
    else
    {
    // Get downloaded asset bundle
    AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
    }
    }
    }
     
  11. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Code looks good. Try commenting out the last line where you actually extract the asset bundle. Most likely the crash is because there is something wrong with the bundle.
     
  12. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    this is code copied verbatim from your documentation:

    https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequestAssetBundle.GetAssetBundle.html

    it never gets to the AssetBundle content call; it crashes immediately at this line:

    yield return uwr.SendWebRequest();

    sometimes it succeeds, but if you point it at a bundle it doesn't like it is guaranteed to crash immediately. The only time it doesn't crash is if the URL is invalid, then you get a 404
     
  13. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Still looks like an issue with the bundle. Replace UnityWebRequestAssetBundle.GetAssetBundle with UnityWebRequest.Get and if it doesn't crash, then it's an issue with AssetBundle.
    Which version are you using, on which platform and which version did you use to build bundles?
     
  14. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Also, this does looks like a bug. It should fail to load incompatible bundles, but it certainly shouldn't crash.
     
    amcakebread likes this.
  15. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    it's worse than crashing - it dumps you out of Unity immediately

    even trying to bypass the example code with this causes an immediate fatal crash

    uint version = 0;
    string url = "https://www.google.com";
    UnityWebRequest uwr = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET, new DownloadHandlerAssetBundle(url, version), null);
    yield return uwr.SendWebRequest();//crashes here
     
  16. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    version was specified in my original reply - it the latest official release: Unity 2018.3.6f1
    also running on windows 10 - the bundle is not especially relevant - it crashes long before it gets a look in but I have built bundles and loaded them successfully in the past for all platforms including windows and WebGL - this is the app I am maintaining but I am not currently attempting to load WebGL bundles
     
  17. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    for clarity, your sample modified as follows causes an immediate crash to desktop

    using (UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle("http://www.my-server.com/mybundle"))
    {
    yield return uwr.SendWebRequest();

    if (uwr.isNetworkError || uwr.isHttpError)
    {
    Debug.Log(uwr.error);
    }
    else
    {
    // Get downloaded asset bundle
    //AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(uwr);
    Debug.Log("succeed");//never gets here
    }
    }
     
  18. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    thank you for your help by the way, this is the first time I have posted a support request and someone has actually responded!
     
  19. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    UnityWebRequest feeds the bundle to AssetBundle system on the fly. If you switch to UnityWebRequest.Get, then you would just download the bytes, so no crash would mean a very high chance the issue is with the bundle and not with UWR.
    You can also try putting the bundle in StreamingAssets and loading it using this API:
    https://docs.unity3d.com/ScriptReference/AssetBundle.LoadFromFileAsync.html
    If it crashes, that would pin point the issue being with bundles.
     
  20. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    I promise you the problem is with UnityWebRequestAssetBundle. I had the exact same issue before with the old system (WWW.LoadFromCacheOrDownload) in that it would forcibly crash in exactly the same way but only if it encountered incompatible asset bundles. The new system crashes even when the bundles are valid so it is completely useless. I am going back to my old system for now and I have pragma'd out the warnings.. FYI this is my current working system:

    public static class AssetBundleUtility
    {
    #pragma warning disable 0618
    public static IEnumerator GetAssetBundle(string url, int version, System.Action<AssetBundle> result)
    {
    using (var www = WWW.LoadFromCacheOrDownload(url, version))
    {
    yield return www;
    if (true == string.IsNullOrEmpty(www.error))
    {
    if (null != www.assetBundle)
    {
    result(www.assetBundle);
    yield break;
    }
    }
    result(null);
    }
    }
    #pragma warning restore 0618
    }

    called as follows:

    yield return AssetBundleUtility.GetAssetBundle(url, (int)BundleVersion.version, value => roomBundle = value);
     
  21. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    This is NOT TRUE!
    In 2018.3 WWW is a wrapper on top of UnityWebRequest and WWW.LoadFromCacheOrDownload is exactly a wrapper on top of UnityWebRequestAssetBundle.GetAssetBundle.

    The system does work and is tested! That is why I asked you all those questions: I'm trying to find out the exact conditions under which you get a crash. There must be something specific in your case that causes the crash.
     
  22. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    all you have to do is follow the instructions in the OP. Start a new project in current release of Unity (2018.3.6f1) on a Windows10 64 machine, create a script as per the Unity example and attach it to a GameObject in the scene . Try to load any AssetBundle from anywhere on the internet (valid or otherwise) and it will crash out of Unity before it even attempts to extract the assetBundle from the data i.e.when this is invoked: SendWebRequest(). It's 100% reliable. If you pass an invalid URL it fails with a 404 as you would expect

    Unity example here:

    https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequestAssetBundle.GetAssetBundle.html
     
  23. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    I think it's important to note that if you have ever successfully loaded the AssetBundle it will continue to 'load' without problem. If you change the version number though it will immediately fail again with a crash. This is one of the problems that had me so confused. Because I had old successfully loaded AssetBundles with the old system, they were cached, so when I changed to the new system everything seemed fine at first. It was only after I tried to load new assetBundles that it crashed horribly. If you want to reproduce the problem you'll need to clear out your cached asset bundles or bump the version number
     
  24. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    OK FYI I have found this is completely compatible with my old system, I have had to add an extra '0' as an argument, but I can now load AssetBundles with version without it crashing Unity.. This is a very brittle system but as long as the AssetBundles are valid and available at the URL then Unity continues functioning.. Any problem at all with the assetBundle at the location results in an immediate crash, and especially if I do not add the last '0' in the versioned loader

    public static IEnumerator GetAssetBundle(string url, uint version, System.Action<AssetBundle> result)
    {
    using (UnityWebRequest uwr = UnityWebRequestAssetBundle.GetAssetBundle(url, version, 0))//notice the last argument
    {
    yield return uwr.SendWebRequest();
    if (false==uwr.isNetworkError && false == uwr.isHttpError)
    {
    result(DownloadHandlerAssetBundle.GetContent(uwr));
    yield break;
    }
    }
    result(null);
    }
     
  25. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Could you report this as a bug (with an actual asset bundle for us to test). It shouldn't crash on incompatible bundles, so it is something for us to look into (and apparently our tests are missing some scenario).
     
    amcakebread likes this.
  26. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28
    yes I'll be happy to do this. If you would like me to email you personally I can do that. Further to this thread I think part of the problem is when some sort of corrupted / bad asset bundle has made it into the local cache. After that it doesn't seem to matter what you do with the code, it just fatally crashes out. It might be that some of the steps I have suggested are only valid in this context so I apologise if you have tried to reproduce the problem without success. As I said at the start though I do promise you that Unity just exits out without warning under certain circumstances and specifically when that function is invoked: yield return uwr.SendWebRequest(); regardless of whether the DownloadHandlerAssetBundle.GetContent(uwr) is even present in the code
     
  27. amcakebread

    amcakebread

    Joined:
    Nov 8, 2016
    Posts:
    28