{"record":{"id":"217536d9f40b2d30","repo":"BabylonJS/Babylon.js","slug":"gaussiansplattingdownloadmanager-has-been-disposed","errorCode":null,"errorMessage":"GaussianSplattingDownloadManager has been disposed.","messagePattern":"GaussianSplattingDownloadManager has been disposed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/loaders/src/SPLAT/gaussianSplattingDownloadManager.ts","lineNumber":99,"sourceCode":"    }\r\n\r\n    /**\r\n     * Whether there are no downloads queued or in flight.\r\n     */\r\n    public get isIdle(): boolean {\r\n        return this._pending.size === 0;\r\n    }\r\n\r\n    /**\r\n     * Downloads a file as an `ArrayBuffer`, queued behind the concurrency cap and retried on failure.\r\n     * Concurrent requests for the same URL resolve from a single shared download.\r\n     * @param url the file URL to download\r\n     * @param groupId optional group tag so related downloads can be cancelled together via {@link cancelGroup}\r\n     * @returns a promise resolving with the downloaded bytes\r\n     */\r\n    public async loadFileAsync(url: string, groupId?: DownloadGroupId): Promise<ArrayBuffer> {\r\n        if (this._disposed) {\r\n            throw new Error(\"GaussianSplattingDownloadManager has been disposed.\");\r\n        }\r\n        const existing = this._pending.get(url);\r\n        if (existing) {\r\n            return await existing.promise;\r\n        }\r\n        const task: IDownloadTask = {\r\n            url,\r\n            groupId,\r\n            settled: false,\r\n            cancelled: false,\r\n            started: false,\r\n            slotReleased: false,\r\n        } as IDownloadTask;\r\n        task.promise = new Promise<ArrayBuffer>((resolve, reject) => {\r\n            task.resolve = resolve;\r\n            task.reject = reject;\r\n        });\r\n        this._pending.set(url, task);\r","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/loaders/src/SPLAT/gaussianSplattingDownloadManager.ts#L81-L117","documentation":"The GaussianSplattingDownloadManager coordinates shared/pending SPLAT file downloads and can be disposed via its dispose() method. Once disposed, loadFileAsync refuses all new work with this error. It signals use-after-dispose: the manager's internal state (pending tasks, abort controllers) has been torn down and cannot accept downloads.","triggerScenarios":"Calling loadFileAsync after GaussianSplattingDownloadManager.dispose() was invoked, e.g. loading another splat file with the same manager instance after a scene/mesh was disposed.","commonSituations":"Reusing a loader/manager across scene reloads; disposing a GaussianSplatting mesh then attempting to stream another file through the same manager; race between an async load and scene disposal.","solutions":["Create a new GaussianSplattingDownloadManager instance after disposing the previous one.","Restructure code so dispose() is only called after all loadFileAsync promises settle.","Guard call sites with a disposed check or a flag reset when reinitializing the scene.","If using framework lifecycle hooks, bind the manager's lifetime to the engine/scene instead of a component that unmounts early."],"exampleFix":"// before\nmanager.dispose();\nawait manager.loadFileAsync(url); // throws\n// after\nmanager.dispose();\nmanager = new GaussianSplattingDownloadManager();\nawait manager.loadFileAsync(url);","handlingStrategy":"try-catch","validationCode":"let manager: GaussianSplattingDownloadManager | null = getManager();\nif (!manager) {\n  manager = new GaussianSplattingDownloadManager(); // recreate if disposed\n}","typeGuard":"function isManagerUsable(m: GaussianSplattingDownloadManager | null): m is GaussianSplattingDownloadManager {\n  return m !== null && !m.isDisposed; // track via your own flag if not exposed\n}","tryCatchPattern":"try {\n  const data = await manager.loadFileAsync(url, groupId);\n} catch (e) {\n  if (String(e.message).includes(\"has been disposed\")) {\n    manager = new GaussianSplattingDownloadManager();\n    return manager.loadFileAsync(url, groupId);\n  }\n  throw e;\n}","preventionTips":["Never call dispose() while loadFileAsync promises are still pending.","Tie the manager's lifetime to the engine/scene, not to a short-lived component.","Recreate the manager after disposal instead of reusing the instance.","Track in-flight downloads with cancelGroup so disposal doesn't race active loads."],"tags":["splat","lifecycle","use-after-dispose","download-manager"],"backgroundTag":"use-after-dispose","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}