{"record":{"id":"3fbd08b009c687b4","repo":"BabylonJS/Babylon.js","slug":"cannot-create-the-xr-graphics-binding-the-engine","errorCode":null,"errorMessage":"Cannot create the XR graphics binding: the engine has been disposed.","messagePattern":"Cannot create the XR graphics binding: the engine has been disposed\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"packages/dev/core/src/XR/webXRSessionManager.ts","lineNumber":307,"sourceCode":"            throw new RangeError(\"The XR view index must be a non-negative integer.\");\r\n        }\r\n\r\n        const pose = this.currentFrame.getViewerPose(this.referenceSpace);\r\n        if (!pose || viewIndex >= pose.views.length) {\r\n            throw new RangeError(`XR view ${viewIndex} is not available in the current viewer pose.`);\r\n        }\r\n        return pose.views[viewIndex];\r\n    }\r\n\r\n    /**\r\n     * Obtains the XR graphics binding for the current session, creating it lazily.\r\n     * This is the API-agnostic seam used by WebGL and WebGPU XR features to share a binding.\r\n     * @returns the XR graphics binding for the current session\r\n     * @internal\r\n     */\r\n    public _getGraphicsBinding(): WebXRGraphicsBinding {\r\n        if (!this._engine) {\r\n            throw new Error(\"Cannot create the XR graphics binding: the engine has been disposed.\");\r\n        }\r\n        if (!this.session) {\r\n            throw new Error(\"Cannot create the XR graphics binding before the XR session is initialized.\");\r\n        }\r\n        if (!this._graphicsBinding) {\r\n            this._graphicsBinding = this._engine.isWebGPU\r\n                ? WebXRWebGPUGraphicsBinding.CreateFromEngine(this.session, this._engine)\r\n                : WebXRWebGLGraphicsBinding.CreateFromEngine(this.session, this._engine);\r\n        }\r\n        return this._graphicsBinding;\r\n    }\r\n\r\n    /**\r\n     * Creates a WebXRRenderTarget object for the XR session\r\n     * @param options optional options to provide when creating a new render target\r\n     * @returns a WebXR render target to which the session can render\r\n     */\r\n    public getWebXRRenderTarget(options?: WebXRManagedOutputCanvasOptions): WebXRRenderTarget {\r","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/XR/webXRSessionManager.ts#L289-L325","documentation":"_getGraphicsBinding() lazily creates the XRGraphicsBinding (WebGL or WebGPU) that lets WebXR layers share GPU resources with the engine. It relies on the stored engine reference (_engine); once the engine has been disposed that reference is nulled, and creating a graphics binding is impossible, so the manager throws.","triggerScenarios":"Calling _getGraphicsBinding() (directly or via WebXR features/layers) after engine.dispose(); a WebXR layer/feature trying to (re)create a binding during teardown or after a scene/engine rebuild while an old session manager still lives.","commonSituations":"Disposing the engine but leaving the XR session manager alive; recreating the engine on resize/context-loss while an XR session manager from the old engine is still referenced; ordering bug in app shutdown where XR cleanup runs after engine.dispose().","solutions":["Dispose the XR session manager (sessionManager.dispose() and end the session) BEFORE calling engine.dispose().","Recreate the WebXR session manager (and its features) after creating a new engine instead of reusing the old one.","Guard usage: check that the engine is alive (not disposed) before invoking XR layer/feature code that needs a graphics binding.","Fix app teardown ordering so XR teardown happens first in your exit/dispose path."],"exampleFix":"// before\nengine.dispose();\nawait xrSessionManager.endSession(); // later code needs binding -> throws\n// after\nawait xrSessionManager.endSession();\nxrSessionManager.dispose();\nengine.dispose();","handlingStrategy":"try-catch","validationCode":"if (xr._engine == null /* engine disposed */) {\n  throw new Error('Refusing to create XR graphics binding: engine disposed');\n}","typeGuard":"function engineAlive(xr: WebXRSessionManager): boolean {\n  // @ts-expect-error internal\n  return xr._engine != null;\n}","tryCatchPattern":"try {\n  const binding = xr._getGraphicsBinding();\n} catch (e) {\n  if (e instanceof Error && e.message.includes('engine has been disposed')) {\n    rebuildEngineAndXR(); // recreate engine + session manager\n    return;\n  }\n  throw e;\n}","preventionTips":["Always end/dispose the XR session manager before engine.dispose()","Never reuse a session manager across engine lifecycles","Track engine disposal state and disable XR paths when disposed","Fix shutdown ordering: XR teardown -> scene dispose -> engine.dispose()"],"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"}