BabylonJS/Babylon.js · critical

WebXRWebGLRenderTargetTextureProvider requires a WebGL-capab

Error message

WebXRWebGLRenderTargetTextureProvider requires a WebGL-capable engine.

What it means

_createInternalTexture wraps a raw WebGLTexture handed over by the XR compositor into a Babylon InternalTexture. It casts the engine to ThinEngine and reads its WebGL context (_gl). If the engine has no GL context (e.g. a WebGPU engine or an engine whose context was lost/disposed), the wrapping cannot proceed and this error is thrown.

Source

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

import { type ThinEngine } from "../Engines/thinEngine";
import { WebGLHardwareTexture } from "../Engines/WebGL/webGLHardwareTexture";
import { type WebGLRenderTargetWrapper } from "../Engines/WebGL/webGLRenderTargetWrapper";
import { InternalTexture, InternalTextureSource } from "../Materials/Textures/internalTexture";
import { type RenderTargetTexture } from "../Materials/Textures/renderTargetTexture.pure";
import { type Nullable } from "../types";
import { WebXRLayerRenderTargetTextureProvider } from "./webXRRenderTargetTextureProvider";
import { type WebXRLayerType, type WebXRSupportedLayerType } from "./webXRLayerWrapper";

/**
 * Provides render target textures for WebGL-backed XR layers. Owns all WebGL-specific
 * framebuffer/texture wiring so the base provider can stay graphics-API-agnostic.
 * @internal
 */
export abstract class WebXRWebGLRenderTargetTextureProvider<LayerTypeT extends WebXRSupportedLayerType = WebXRLayerType> extends WebXRLayerRenderTargetTextureProvider<LayerTypeT> {
    private _createInternalTexture(textureSize: { width: number; height: number }, texture: WebGLTexture): InternalTexture {
        const gl = (this._engine as ThinEngine)._gl;
        if (!gl) {
            throw new Error("WebXRWebGLRenderTargetTextureProvider requires a WebGL-capable engine.");
        }
        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) {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Create the app engine as a WebGL ThinEngine when using WebGL-based XR sessions (matching WebXRWebGLGraphicsBinding), not WebGPU.
  2. Use the WebGPU-specific XR path/binding (WebXRWebGPUGraphicsBinding and its texture provider) when the engine is WebGPU.
  3. Check `engine.isWebGL` / `(engine as ThinEngine)._gl` before setting up XR render target textures and choose the right provider.
  4. Recreate the WebGL context / engine if it was lost, then restart the XR session before requesting render target textures.

Example fix

// before
const engine = new WebGPUEngine(canvas); // but using WebGL XR session layer
const xrRTT = new WebXRWebGLRenderTargetTextureProvider(engine, xr); // throws
// after
const engine = new Engine(canvas, true); // WebGL engine for WebGL XR session
const xrRTT = new WebXRWebGLRenderTargetTextureProvider(engine, xr);
Defensive patterns

Strategy: type-guard

Validate before calling

import { ThinEngine } from '@babylonjs/core/Engines/thinEngine';
const gl = (engine as ThinEngine)._gl;
if (!gl) {
  throw new Error('Cannot set up WebGL XR render targets: no WebGL context');
}

Type guard

function isWebGLEngine(engine: AbstractEngine): engine is ThinEngine {
  return !engine.isWebGPU && !!(engine as ThinEngine)._gl;
}

Try / catch

try {
  const rtt = provider.getRenderTargetTextureForEye(eye);
} catch (e) {
  if (e instanceof Error && e.message.includes('WebGL-capable engine')) {
    console.error('Wrong engine type for WebGL XR session:', e.message);
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Using a WebXR render target texture provider (WebXRWebGLRenderTargetTextureProvider._createRenderTargetTexture / internalTexture) with a WebGPU engine or an engine where _gl is null (context lost, engine disposed, NullEngine).

Common situations: Mixing WebGPU engine with a WebGL-only XR session (requestSession without gl context / wrong graphics binding type); running XR in a NullEngine test environment; engine context loss during an active XR session.

Related errors


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