{"record":{"id":"be1ac3215185cb4e","repo":"BabylonJS/Babylon.js","slug":"engine-is-disposed","errorCode":null,"errorMessage":"Engine is disposed","messagePattern":"Engine is disposed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/dev/core/src/XR/webXRWebGLRenderTargetTextureProvider.ts","lineNumber":38,"sourceCode":"        }\n        const internalTexture = new InternalTexture(this._engine, InternalTextureSource.Unknown, true);\n        internalTexture.width = textureSize.width;\n        internalTexture.height = textureSize.height;\n        internalTexture._hardwareTexture = new WebGLHardwareTexture(texture, gl);\n        internalTexture.isReady = true;\n        return internalTexture;\n    }\n\n    protected _createRenderTargetTexture(\n        width: number,\n        height: number,\n        framebuffer: Nullable<WebGLFramebuffer>,\n        colorTexture?: WebGLTexture,\n        depthStencilTexture?: WebGLTexture,\n        multiview?: boolean\n    ): RenderTargetTexture {\n        if (!this._engine) {\n            throw new Error(\"Engine is disposed\");\n        }\n\n        const textureSize = { width, height };\n\n        const renderTargetTexture = this._createRenderTargetTextureShell(width, height, !!multiview);\n        const renderTargetWrapper = renderTargetTexture.renderTarget as WebGLRenderTargetWrapper;\n        // Set the framebuffer, make sure it works in all scenarios - emulator, no layers and layers.\n        // This must happen before binding any texture, since setTexture binds it to the framebuffer.\n        if (framebuffer || !colorTexture) {\n            renderTargetWrapper._framebuffer = framebuffer;\n        }\n\n        // Create internal texture\n        if (colorTexture) {\n            if (multiview) {\n                renderTargetWrapper._colorTextureArray = colorTexture;\n            } else {\n                const internalTexture = this._createInternalTexture(textureSize, colorTexture);","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/XR/webXRWebGLRenderTargetTextureProvider.ts#L20-L56","documentation":"_createRenderTargetTexture builds a Babylon RenderTargetTexture around the XR layer's framebuffer/color texture. The provider stores an engine reference; if the engine was disposed (reference cleared), creating new GPU resources is impossible and this error is thrown before any allocation.","triggerScenarios":"Requesting getRenderTargetTextureForEye(...) (or a layer RTT refresh) after engine.dispose(); an XR frame callback still running while the engine is being torn down; reusing a texture provider created with an old engine after engine recreation.","commonSituations":"Shutdown-order bug: engine.dispose() before ending the XR session; app teardown where XR compositor calls back into a disposed provider; swapping engines (context loss recovery) without rebuilding XR providers.","solutions":["End the XR session and dispose XR providers before engine.dispose().","Guard calls with a liveness check (`if (provider is alive)` / check engine not disposed) before fetching render target textures.","Recreate the XR session manager, layers and texture providers after building a new engine.","Defer/ignore render-target requests during teardown (e.g. null out frame callbacks first)."],"exampleFix":"// before\nengine.dispose();\nconst rtt = provider.getRenderTargetTextureForEye(eye); // throws\n// after\nconst rtt = provider.getRenderTargetTextureForEye(eye);\nprovider.dispose?.();\nengine.dispose();","handlingStrategy":"try-catch","validationCode":"if (!provider || provider._engine == null /* disposed */) {\n  return null; // engine disposed; cannot create RTT\n}","typeGuard":"function providerUsable(provider: WebXRWebGLRenderTargetTextureProvider): boolean {\n  // @ts-expect-error internal\n  return provider._engine != null;\n}","tryCatchPattern":"try {\n  const rtt = provider.getRenderTargetTextureForEye(eye);\n} catch (e) {\n  if (e instanceof Error && e.message === 'Engine is disposed') {\n    console.warn('Skipping XR RTT fetch during engine teardown');\n    return null;\n  }\n  throw e;\n}","preventionTips":["End the XR session and dispose providers before engine.dispose()","Null out XR frame callbacks before teardown so late requests are avoided","Rebuild XR providers when recreating an engine after context loss","Guard render-target fetches with an engine-alive check"],"tags":["webxr","engine-disposed","lifecycle"],"backgroundTag":"engine-disposed","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}