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

  1. Dispose the XR session manager (sessionManager.dispose() and end the session) BEFORE calling engine.dispose().
  2. Recreate the WebXR session manager (and its features) after creating a new engine instead of reusing the old one.
  3. Guard usage: check that the engine is alive (not disposed) before invoking XR layer/feature code that needs a graphics binding.
  4. 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

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


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/3fbd08b009c687b4. Report an issue: GitHub.