{"record":{"id":"9aaa37e53bddd37c","repo":"stride3d/stride","slug":"bundle-has-not-been-loaded","errorCode":null,"errorMessage":"Bundle has not been loaded.","messagePattern":"Bundle has not been loaded\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"sources/core/Stride.Core.Serialization/Storage/BundleOdbBackend.cs","lineNumber":299,"sourceCode":"    {\n        if (bundleName == null) throw new ArgumentNullException(nameof(bundleName));\n\n        lock (loadedBundles)\n        {\n            int loadedBundleIndex = -1;\n\n            for (int index = 0; index < loadedBundles.Count; index++)\n            {\n                var currentBundle = loadedBundles[index];\n                if (currentBundle.BundleName == bundleName)\n                {\n                    loadedBundleIndex = index;\n                    break;\n                }\n            }\n\n            if (loadedBundleIndex == -1)\n                throw new InvalidOperationException(\"Bundle has not been loaded.\");\n\n            var loadedBundle = loadedBundles[loadedBundleIndex];\n            var bundle = loadedBundle.Description;\n            if (--loadedBundle.ReferenceCount == 0)\n            {\n                // Remove and dispose stream from pool\n                lock (loadedBundle.Streams)\n                {\n                    for (int index = 0; index < loadedBundle.Streams.Count; index++)\n                    {\n                        var stream = loadedBundle.Streams[index];\n                        stream?.Dispose();\n                        loadedBundle.Streams[index] = null;\n                    }\n                }\n\n                // Actually unload bundle\n                loadedBundles.RemoveAt(loadedBundleIndex);","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/stride3d/stride/blob/96fad776d210c221682aac1ccdf4c79dc046fc38/sources/core/Stride.Core.Serialization/Storage/BundleOdbBackend.cs#L281-L317","documentation":"UnloadBundleRecursive searches loadedBundles for the bundle description being unloaded and throws InvalidOperationException when none matches (loadedBundleIndex == -1). The code attempted to unload a bundle that was never loaded (or already fully unloaded).","triggerScenarios":"Calling UnloadBundle for a bundle name/url never passed to LoadBundle, unloading the same bundle twice, or recursive unloading reaching a dependency already unloaded.","commonSituations":"Shutdown/dispose logic running twice (double Dispose), error-recovery paths that unload bundles after a failed load, or unloading a bundle whose parent already recursively removed it.","solutions":["Track loaded bundles and only call UnloadBundle for bundles previously loaded successfully.","Make unload logic idempotent: skip if the bundle is not currently loaded instead of assuming it is.","Fix double-dispose (guard Dispose with a flag) so unload doesn't run twice."],"exampleFix":"// before\nbackend.UnloadBundle(\"scene.bundle\"); // may throw if never loaded\n// after\nif (backend.IsBundleLoaded(\"scene.bundle\"))\n    backend.UnloadBundle(\"scene.bundle\");","handlingStrategy":"validation","validationCode":"if (!backend.IsBundleLoaded(bundleUrl))\n    return; // nothing to unload\nbackend.UnloadBundle(bundleUrl);","typeGuard":null,"tryCatchPattern":"try\n{\n    backend.UnloadBundle(bundleUrl);\n}\ncatch (InvalidOperationException ex) when (ex.Message == \"Bundle has not been loaded.\")\n{\n    // already unloaded; treat as no-op\n}","preventionTips":["Track load/unload pairs in your own reference counting or use a loaded-set.","Guard Dispose against double execution so unload paths run once.","Let recursive unloading handle dependencies rather than unloading children manually."],"tags":["bundles","invalid-state","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"96fad776d210c221682aac1ccdf4c79dc046fc38","analyzedAt":"2026-09-14T02:59:31.279Z","contentChangedAt":"2026-09-14T02:59:31.279Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}