Unity 6000.0.25f1: Loading AssetBundle crashes the app

Hello, we’re facing a crash that happens both in build and in editor, the error happens rarely so its not related the the specific bundle that is mentioned, after reloading it works fine.
We load and unload asset bundles during session, we also guarded all the operation related to the asset bundle, and we added a delay to not unload a bundle after a loading the bundle for a short time.
These guards seems to reduce the occurrences of the crash but it is still happening

It happens randomly when loading and unloading assetbundles.
Crash Report (1).txt (12.4 KB)

Hi! Our developers took a peek at this:

The issue looks to be caused by a third-party plugin (specifically, the Microsoft Mixed Reality Toolkit) doing some threading (via Await it seems). But it’s still a valid bug. I’m not sure if it’s the asset bundles or the file system, but those successes need to be addressed.

Therefore, if you’re able to find a somewhat consistent reproduction with consistent steps, please report the issue via the Bug Reporter (“Help → Report a Bug…” in the Editor). Make sure to attach your problematic project or a smaller-scale project that can reproduce the same crash. We’ll then look into this further.

Cheers!

Hello @jonabali, reproducing the issue is really hard, because its not related to specific bundles it happening randomly.
We tried to do a small scene and load and unload asset bundles to force it but it didnt work
Mainly the trigger for it was that we have alot of bundles being loaded and unloaded, and then we get the cab issue
Is there any limit to how many bundles can be loaded at the same time? Maybe that might be the issue that we’re loading multiple bundles at ones?

Hey,

It’s tough to say without a repo case, but looking at your logs could it be unloading AssetBundles when Texture Streaming is enabled? We have a bug report we’re fixing right now (a PR is up!) where the logs look awfully similar is all!

Hello @George-Ing, we have mipmap enabled, and we also have the bundles uncompressed for faster loading
One thing we added was when a bundle is loaded, we added a 1 second delay so that in case unloading was requested itll wait till after this delay
If unloading a bundle while its loading mipmaps is probably causing it is there an option to force mipmap loading to finish on the bundle before unloading? If you have any possible fixes, we can try it since we are still unable to have a reproducible small project.

I’ve looked at the code and the “The operation completed successfully” string in the messages should be ignored. They are a bit confusing but it happens when the call fails but there was no specific error message set by the underlying file system. That would be something for us to fix to get clearer error messages.

But as for the more relevant issue of the actual failures. I think this sort of error is a sign of an AssetBundle being accessed AFTER it has been unloaded. E.g. the AssetBundle Archive has been unmounted so the virtual files inside it are no longer available.

So i think its all about tracking down in your code why there is access going on after Unload happens - it may be a threading bug or unsafe use of async calls. For example to make sure to wait until the load has fully completed.

Example:
From one call stack we see:
DLCSystem_LoadHandler_GameObject:LoadFromAssetBundle

which hits
Could not open file archive:/CAB-022814ded1c1376f0f5906bc73fd5f33/CAB-022814ded1c1376f0f5906bc73fd5f33 for read

That makes me think that LoadFromAssetBundle is being called on an AssetBundle that is not loaded.
Or alternatively that the AssetBundle is being loaded but it is not done yet, and there is an attempt to use it too early.

Hope this helps

Hello @AndrewSkow

This is part of the code, the load from asset bundle happens after we load from the bundle, and for the normal flow its working, but i think @George-Ing is correct, the issue seems to be happening only when mipmaps are trying to load, thats why its hard to reproduce

 private async Task LoadFromFile()
 {
        var path = Request.GetFileLocation();
        try
        {
            bundle = await AssetBundle.LoadFromFileAsync(path);
            LoadFromAssetBundle(bundle);
        }
        catch (Exception e)
        {
            HandleError("Load Bundle", e);
        }
    }

    public void LoadFromAssetBundle(AssetBundle bundle)
    {
        try
        {
            prefab = (GameObject)bundle.LoadAsset<GameObject>(Request.subName);
            StartReleaseTimer();
            OnLoadComplete(prefab);
        }
        catch (Exception e)
        {
            HandleError("Load Game Object", e);
        }
    }

Thanks for the details. We’ve had challenges trying to reproduce the sort of errors that you are reporting.

All i can think of suggesting would be add temporary logging of all your async loads, loadasset calls, and unloads to try to see if there is some pattern for when this fails. e.g. any possibility that the loading pattern for one particular AssetBundle ends up overlapped, e.g. a previous request to unload hasn’t fully finished before the next load is triggered. Or that might give some clue about the mipmap involvement if certain bundles look different than others.

Hello @AndrewSkow, switching from Async to normal fixed the issue, but its not a sustainable solution for us
A good way to reproduce wouldbe to have a bundle with a big texture and mipmap enabled, add a call that loads and unloads that bundle repeatedly with some delays while the object is moving forward and backward
I tried alot of delays after loading and unloading but nothing seemed to work so in the end we switched to normal loading

Hey @OmarItani1995 I’m still a bit fuzzy on the exact details of the crash in itself, but from what read in the discussions here I can at least mention the following …

We indeed have a PR looking into AssetBundle unloading when Texture Streaming is active. To be clear, the delay between loading and unloading isn’t necessarily a big factor so I’m not surprised that it doesn’t do that much … Depending on lots of factors, it’s of course perfectly possible for the streamer to make new requests minutes (or even hours?) after a bundle was loaded, it’s really just “bad luck” to have the streamer being active on a specific texture just when its associated bundle unloads (but presumably the streamer has more work when you just open a bundle, so that delay does factor in to some extent). And depending on how tight streaming budgets are, the streamer might be very actively loading and unloading mips, or it might have sufficient capacity and just upload mipmap levels once when necessary (again, if you’re unluckily unloading a bundle just at that point, it can result in issues).

If unloading a bundle while its loading mipmaps is probably causing it is there an option to force mipmap loading to finish on the bundle before unloading?

Unfortunately, no. Depending on how quickly you’d get this implemented at user-side, if you know what textures are streaming you could try and make sure tex.loadingMipmapLevel == tex.loadedMipmapLevel for each texture in the bundle you’re trying to unload; or even force it to a specific level with tex.requestedMipmapLevel and wait for that to be uploaded. But there’s no option to globally force finish uploading (which would arguably have to be done at the Engine side anyway)

To be clear, if you’re hitting the same assetbundle-unload issue that we’re fixing, the user-side checks I mentioned above will not be needed when the fix lands and we shouldn’t be trying to read from closed files anymore.

As for the crash, though, not sure what happens there and whether or not it indicates other AssetBundle issues acting up. Again, it’s a bit fuzzy to me at first sight (like, contrary to the discussions here, the provided crash log doesn’t mention the streamer?) so not sure to what extent this information here is valuable.