BabylonJS/Babylon.js · critical
Cannot create the XR graphics binding: the engine has been d
Error message
Cannot create the XR graphics binding: the engine has been disposed.
What it means
_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.
Source
Thrown at packages/dev/core/src/XR/webXRSessionManager.ts:307
throw new RangeError("The XR view index must be a non-negative integer.");
}
const pose = this.currentFrame.getViewerPose(this.referenceSpace);
if (!pose || viewIndex >= pose.views.length) {
throw new RangeError(`XR view ${viewIndex} is not available in the current viewer pose.`);
}
return pose.views[viewIndex];
}
/**
* Obtains the XR graphics binding for the current session, creating it lazily.
* This is the API-agnostic seam used by WebGL and WebGPU XR features to share a binding.
* @returns the XR graphics binding for the current session
* @internal
*/
public _getGraphicsBinding(): WebXRGraphicsBinding {
if (!this._engine) {
throw new Error("Cannot create the XR graphics binding: the engine has been disposed.");
}
if (!this.session) {
throw new Error("Cannot create the XR graphics binding before the XR session is initialized.");
}
if (!this._graphicsBinding) {
this._graphicsBinding = this._engine.isWebGPU
? WebXRWebGPUGraphicsBinding.CreateFromEngine(this.session, this._engine)
: WebXRWebGLGraphicsBinding.CreateFromEngine(this.session, this._engine);
}
return this._graphicsBinding;
}
/**
* Creates a WebXRRenderTarget object for the XR session
* @param options optional options to provide when creating a new render target
* @returns a WebXR render target to which the session can render
*/
public getWebXRRenderTarget(options?: WebXRManagedOutputCanvasOptions): WebXRRenderTarget {
View on GitHub (pinned to 0592b347b8)
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.
Example fix
// before engine.dispose(); await xrSessionManager.endSession(); // later code needs binding -> throws // after await xrSessionManager.endSession(); xrSessionManager.dispose(); engine.dispose();
Defensive patterns
Strategy: try-catch
Validate before calling
if (xr._engine == null /* engine disposed */) {
throw new Error('Refusing to create XR graphics binding: engine disposed');
} Type guard
function engineAlive(xr: WebXRSessionManager): boolean {
// @ts-expect-error internal
return xr._engine != null;
} Try / catch
try {
const binding = xr._getGraphicsBinding();
} catch (e) {
if (e instanceof Error && e.message.includes('engine has been disposed')) {
rebuildEngineAndXR(); // recreate engine + session manager
return;
}
throw e;
} Prevention
- 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()
When it happens
Trigger: 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.
Common situations: 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().
Related errors
- Engine is disposed
- Restoring persistent anchors requires the anchor system to b
- Persistent anchor restoration was interrupted before trackin
- There is no NavMesh generated.
- There is no TileCache generated.
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/3fbd08b009c687b4.
Report an issue: GitHub.