BabylonJS/Babylon.js · critical

Engine is disposed

Error message

Engine is disposed

What it means

_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.

Source

Thrown at packages/dev/core/src/XR/webXRWebGLRenderTargetTextureProvider.ts:38

        }
        const internalTexture = new InternalTexture(this._engine, InternalTextureSource.Unknown, true);
        internalTexture.width = textureSize.width;
        internalTexture.height = textureSize.height;
        internalTexture._hardwareTexture = new WebGLHardwareTexture(texture, gl);
        internalTexture.isReady = true;
        return internalTexture;
    }

    protected _createRenderTargetTexture(
        width: number,
        height: number,
        framebuffer: Nullable<WebGLFramebuffer>,
        colorTexture?: WebGLTexture,
        depthStencilTexture?: WebGLTexture,
        multiview?: boolean
    ): RenderTargetTexture {
        if (!this._engine) {
            throw new Error("Engine is disposed");
        }

        const textureSize = { width, height };

        const renderTargetTexture = this._createRenderTargetTextureShell(width, height, !!multiview);
        const renderTargetWrapper = renderTargetTexture.renderTarget as WebGLRenderTargetWrapper;
        // Set the framebuffer, make sure it works in all scenarios - emulator, no layers and layers.
        // This must happen before binding any texture, since setTexture binds it to the framebuffer.
        if (framebuffer || !colorTexture) {
            renderTargetWrapper._framebuffer = framebuffer;
        }

        // Create internal texture
        if (colorTexture) {
            if (multiview) {
                renderTargetWrapper._colorTextureArray = colorTexture;
            } else {
                const internalTexture = this._createInternalTexture(textureSize, colorTexture);

View on GitHub (pinned to 0592b347b8)

Solutions

  1. End the XR session and dispose XR providers before engine.dispose().
  2. Guard calls with a liveness check (`if (provider is alive)` / check engine not disposed) before fetching render target textures.
  3. Recreate the XR session manager, layers and texture providers after building a new engine.
  4. Defer/ignore render-target requests during teardown (e.g. null out frame callbacks first).

Example fix

// before
engine.dispose();
const rtt = provider.getRenderTargetTextureForEye(eye); // throws
// after
const rtt = provider.getRenderTargetTextureForEye(eye);
provider.dispose?.();
engine.dispose();
Defensive patterns

Strategy: try-catch

Validate before calling

if (!provider || provider._engine == null /* disposed */) {
  return null; // engine disposed; cannot create RTT
}

Type guard

function providerUsable(provider: WebXRWebGLRenderTargetTextureProvider): boolean {
  // @ts-expect-error internal
  return provider._engine != null;
}

Try / catch

try {
  const rtt = provider.getRenderTargetTextureForEye(eye);
} catch (e) {
  if (e instanceof Error && e.message === 'Engine is disposed') {
    console.warn('Skipping XR RTT fetch during engine teardown');
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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