BabylonJS/Babylon.js · error · RangeError

XR view ${viewIndex} is not available in the current viewer

Error message

XR view ${viewIndex} is not available in the current viewer pose.

What it means

After obtaining the viewer pose for the current frame, _getCurrentXRView checks that viewIndex is within pose.views.length. WebXR may return a pose with fewer views than expected (or no pose at all if the viewer pose is unavailable for this frame), so an out-of-range index throws a RangeError naming the requested view.

Source

Thrown at packages/dev/core/src/XR/webXRSessionManager.ts:294

    }

    private _getCurrentXRView(viewIndex: number): XRView {
        if (!this.inXRSession || !this.session) {
            throw new Error("Dynamic viewport scaling requires an active XR session.");
        }
        if (!this.inXRFrameLoop || !this.currentFrame) {
            throw new Error("Dynamic viewport scaling must be used during an active XR frame.");
        }
        if (!this._referenceSpaceInitialized) {
            throw new Error("Dynamic viewport scaling requires an initialized XR reference space.");
        }
        if (!Number.isInteger(viewIndex) || viewIndex < 0) {
            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) {

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Query the actual view count per frame (pose.views.length via sessionManager or iterate available views) instead of hard-coding indices.
  2. Handle the case where the session is monoscopic: only request view(1) when a second view exists.
  3. Check that the session is still active and rendering before querying views; re-enter the render loop if it stopped.
  4. Fall back to the first view (index 0) or the default viewport when the requested index is unavailable.

Example fix

// before
scaleViewport(xr.view(1)); // assumes stereo
// after
const viewCount = xr.scene.activeCamera ? xr.getNumberOfViews?.() ?? 2 : 2;
if (viewCount > 1) {
  scaleViewport(xr.view(1));
} else {
  scaleViewport(xr.view(0));
}
Defensive patterns

Strategy: fallback

Validate before calling

const pose = xr.currentFrame?.getViewerPose(xr.referenceSpace);
if (!pose || viewIndex >= pose.views.length) {
  return; // view not available this frame
}
const v = xr.view(viewIndex);

Type guard

function viewAvailable(xr: WebXRSessionManager, i: number): boolean {
  const pose = xr.currentFrame?.getViewerPose(xr.referenceSpace);
  return !!pose && i < pose.views.length;
}

Try / catch

try {
  const v = xr.view(1);
  scaleViewport(v);
} catch (e) {
  if (e instanceof RangeError && e.message.includes('not available')) {
    scaleViewport(xr.view(0)); // monoscopic fallback
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling view(1) or view(2) when the session currently exposes only one view (e.g. a monoscopic/phone AR session); querying a view index right after entering/exiting a session where the pose is null; hardware configuration changes between frames.

Common situations: Hard-coding two eyes (view(0) and view(1)) but running in an immersive-ar mode that provides one view; getSession().renderState changes; a frame where getViewerPose returns null due to tracking loss or session pause.

Related errors


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