BabylonJS/Babylon.js · error · RangeError

The XR view index must be a non-negative integer.

Error message

The XR view index must be a non-negative integer.

What it means

The viewIndex argument passed to _getCurrentXRView (via view()) must be a whole number >= 0 because it indexes into pose.views, a JavaScript array of XRViews. Non-integer or negative values can never map to a view, so a RangeError is thrown up front before any WebXR API is touched.

Source

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

        const view = this._getCurrentXRView(viewIndex);
        if (!("recommendedViewportScale" in view) || typeof view.requestViewportScale !== "function") {
            throw new Error(`Dynamic viewport scaling is not supported for XR view ${viewIndex}.`);
        }
        view.requestViewportScale(scale);
    }

    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.");

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Pass a non-negative integer index (0, 1, ...) matching the eye/view you want.
  2. Sanitize the value first: use Math.floor for derived floats and validate `Number.isInteger(i) && i >= 0` before the call.
  3. If you have an eye constant, map it to the correct integer index before calling view().
  4. Loop over views using pose.views.length bounds rather than a hard-coded upper limit.

Example fix

// before
const idx = eyes.length / 2; // 1.5 -> throws
const v = xr.view(idx);
// after
const idx = Math.floor(eyes.length / 2);
if (Number.isInteger(idx) && idx >= 0) {
  const v = xr.view(idx);
}
Defensive patterns

Strategy: validation

Validate before calling

const viewIndex: unknown = getUserIndex();
if (typeof viewIndex !== 'number' || !Number.isInteger(viewIndex) || viewIndex < 0) {
  throw new RangeError('view index must be a non-negative integer');
}
const v = xr.view(viewIndex);

Type guard

function isValidXRViewIndex(i: unknown): i is number {
  return typeof i === 'number' && Number.isInteger(i) && i >= 0;
}

Try / catch

try {
  const v = xr.view(idx);
} catch (e) {
  if (e instanceof RangeError && e.message.includes('non-negative integer')) {
    console.error(`Bad view index: ${idx}`);
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling view(-1), view(0.5), view(NaN) or view(undefined coerced) — typically from a loop with a wrong bound, from Math.random-derived values, or by passing an eye identifier string/enum instead of an integer index.

Common situations: Iterating views with a wrong increment; confusing eye enums (LEFT/RIGHT) with numeric indices; a variable that was expected to be an eye index but holds a float from a division or a NaN from a failed parse.

Related errors


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