Quick answer: AssetBundle errors are almost always caused by (1) wrong build target, (2) missing dependency bundles, or (3) cached hash mismatch after a rebuild. Load the manifest first, check dependencies, verify the platform, and clear Caching.ClearCache() when iterating.

AssetBundles are Unity's most powerful content-streaming feature and also its most error-prone. You build bundles in the editor, ship them with your game (or host them on a CDN), and at runtime LoadFromFile returns null — or worse, succeeds but returns nothing when you ask for the asset. The error messages are cryptic, the documentation is sparse, and the debugging is a process of elimination. Here is that process, in order.

The Symptom

Common error patterns you will see in the Unity console or player log:

Unable to open archive file: /storage/emulated/0/Android/data/.../characters
The AssetBundle 'characters' can't be loaded because another AssetBundle
  with the same files is already loaded.
AssetBundle couldn't be loaded because it references scripts that are not
  available for the target platform.
The file cannot be loaded because it was created for another build target.

Or silent failures: AssetBundle.LoadFromFile returns null, LoadAsset<T> returns null, or the asset loads but instantiating it produces a pink/magenta placeholder because its shader dependency is missing.

What Causes This

1. Wrong build target. AssetBundles are platform-specific. A bundle built with BuildTarget.StandaloneWindows64 will not load on Android, iOS, or even StandaloneLinux64. This is the most common bug when you use a CI pipeline that builds bundles for only one platform.

2. Missing dependency bundles. When you assign assets to bundle A and they reference assets in bundle B (via a Prefab pointing to a shared shader or material), Unity splits them into two bundles. Loading A without first loading B leaves the references dangling.

3. Hash mismatch. Bundles have a CRC hash. When you rebuild with changed content, the hash changes. If you cached the old bundle in Caching.cache and try to re-download with a different hash, Unity will either use the stale cached version or fail depending on how you are loading.

4. Duplicate bundle names. If you load a bundle, forget to unload it, and then try to load it again, Unity errors out with "another AssetBundle with the same files is already loaded."

5. Scripts baked into the bundle. If your bundle contains ScriptableObjects or Prefabs with MonoBehaviour components, those scripts must exist in the main build. Building the bundle with a different version of the script than the main build causes "references scripts that are not available" errors.

The Fix

Step 1: Load the manifest and inspect dependencies first.

using UnityEngine;
using System.IO;

public class BundleLoader : MonoBehaviour
{
    AssetBundleManifest manifest;

    void Awake()
    {
        string root = Path.Combine(Application.streamingAssetsPath, "Bundles");
        string manifestPath = Path.Combine(root, "Bundles");
        AssetBundle manifestBundle = AssetBundle.LoadFromFile(manifestPath);
        manifest = manifestBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
    }

    public AssetBundle LoadWithDependencies(string bundleName, string root)
    {
        // Load all dependencies first (recursively resolved)
        string[] deps = manifest.GetAllDependencies(bundleName);
        foreach (var dep in deps)
        {
            AssetBundle.LoadFromFile(Path.Combine(root, dep));
        }
        return AssetBundle.LoadFromFile(Path.Combine(root, bundleName));
    }
}

The manifest bundle is built alongside your content and is named after the build folder. It contains the list of bundles and their dependency graph. Always load dependencies before the main bundle, or Unity will fail to resolve cross-bundle references.

Step 2: Verify the bundle matches the current platform.

string platformFolder = GetPlatformFolder();
string bundlePath = Path.Combine(
    Application.streamingAssetsPath, "Bundles", platformFolder, "characters"
);

static string GetPlatformFolder()
{
    #if UNITY_STANDALONE_WIN
        return "Windows";
    #elif UNITY_STANDALONE_OSX
        return "macOS";
    #elif UNITY_ANDROID
        return "Android";
    #elif UNITY_IOS
        return "iOS";
    #elif UNITY_WEBGL
        return "WebGL";
    #else
        return "Unknown";
    #endif
}

Build bundles once per platform in your CI pipeline and store them in subfolders keyed by platform name. At runtime, pick the right folder with a preprocessor check.

Step 3: Clear the cache when iterating.

If you are hosting bundles on a server and using UnityWebRequestAssetBundle with caching, hash mismatches during development can leave stale bundles in the cache. Clear it manually when testing new builds:

#if UNITY_EDITOR
if (Input.GetKeyDown(KeyCode.F9))
{
    Caching.ClearCache();
    Debug.Log("AssetBundle cache cleared");
}
#endif

Or use a hash from the manifest when downloading so Unity skips the cache when content changes:

Hash128 hash = manifest.GetAssetBundleHash(bundleName);
UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(url, hash, 0);
yield return www.SendWebRequest();

Step 4: Always unload before reloading.

public void ReloadBundle(string name)
{
    if (loadedBundles.TryGetValue(name, out var existing))
    {
        existing.Unload(true);  // true = unload loaded assets too
        loadedBundles.Remove(name);
    }
    var bundle = AssetBundle.LoadFromFile(GetPath(name));
    loadedBundles[name] = bundle;
}

The true parameter on Unload destroys any objects already instantiated from the bundle. Pass false if you want to keep currently-instantiated objects alive but free the bundle's memory.

Step 5: Consider switching to Addressables.

If you are fighting AssetBundles regularly, Addressables solves most of these problems by wrapping the raw API with dependency resolution, hash management, and automatic platform selection. The migration cost is a weekend of refactoring for most projects. See Unity Addressables failed to load for common post-migration issues.

"AssetBundles are the reason Addressables exists. If you have the budget for a migration, do it. If not, make peace with the manifest."

Related Issues

For dependency and memory issues in the Addressables system see addressable groups build size too large. For the underlying memory pressure that often unmasks bundle bugs, see addressables memory not releasing.

Always load the manifest first. Always check dependencies. Always build per platform. No exceptions.