{"record":{"id":"0c2b5d6635733149","repo":"BabylonJS/Babylon.js","slug":"xr-view-viewindex-is-not-available-in-the-curre","errorCode":null,"errorMessage":"XR view ${viewIndex} is not available in the current viewer pose.","messagePattern":"XR view (.+?) is not available in the current viewer pose\\.","errorType":"exception","errorClass":"RangeError","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/XR/webXRSessionManager.ts","lineNumber":294,"sourceCode":"    }\r\n\r\n    private _getCurrentXRView(viewIndex: number): XRView {\r\n        if (!this.inXRSession || !this.session) {\r\n            throw new Error(\"Dynamic viewport scaling requires an active XR session.\");\r\n        }\r\n        if (!this.inXRFrameLoop || !this.currentFrame) {\r\n            throw new Error(\"Dynamic viewport scaling must be used during an active XR frame.\");\r\n        }\r\n        if (!this._referenceSpaceInitialized) {\r\n            throw new Error(\"Dynamic viewport scaling requires an initialized XR reference space.\");\r\n        }\r\n        if (!Number.isInteger(viewIndex) || viewIndex < 0) {\r\n            throw new RangeError(\"The XR view index must be a non-negative integer.\");\r\n        }\r\n\r\n        const pose = this.currentFrame.getViewerPose(this.referenceSpace);\r\n        if (!pose || viewIndex >= pose.views.length) {\r\n            throw new RangeError(`XR view ${viewIndex} is not available in the current viewer pose.`);\r\n        }\r\n        return pose.views[viewIndex];\r\n    }\r\n\r\n    /**\r\n     * Obtains the XR graphics binding for the current session, creating it lazily.\r\n     * This is the API-agnostic seam used by WebGL and WebGPU XR features to share a binding.\r\n     * @returns the XR graphics binding for the current session\r\n     * @internal\r\n     */\r\n    public _getGraphicsBinding(): WebXRGraphicsBinding {\r\n        if (!this._engine) {\r\n            throw new Error(\"Cannot create the XR graphics binding: the engine has been disposed.\");\r\n        }\r\n        if (!this.session) {\r\n            throw new Error(\"Cannot create the XR graphics binding before the XR session is initialized.\");\r\n        }\r\n        if (!this._graphicsBinding) {\r","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/XR/webXRSessionManager.ts#L276-L312","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Query the actual view count per frame (pose.views.length via sessionManager or iterate available views) instead of hard-coding indices.","Handle the case where the session is monoscopic: only request view(1) when a second view exists.","Check that the session is still active and rendering before querying views; re-enter the render loop if it stopped.","Fall back to the first view (index 0) or the default viewport when the requested index is unavailable."],"exampleFix":"// before\nscaleViewport(xr.view(1)); // assumes stereo\n// after\nconst viewCount = xr.scene.activeCamera ? xr.getNumberOfViews?.() ?? 2 : 2;\nif (viewCount > 1) {\n  scaleViewport(xr.view(1));\n} else {\n  scaleViewport(xr.view(0));\n}","handlingStrategy":"fallback","validationCode":"const pose = xr.currentFrame?.getViewerPose(xr.referenceSpace);\nif (!pose || viewIndex >= pose.views.length) {\n  return; // view not available this frame\n}\nconst v = xr.view(viewIndex);","typeGuard":"function viewAvailable(xr: WebXRSessionManager, i: number): boolean {\n  const pose = xr.currentFrame?.getViewerPose(xr.referenceSpace);\n  return !!pose && i < pose.views.length;\n}","tryCatchPattern":"try {\n  const v = xr.view(1);\n  scaleViewport(v);\n} catch (e) {\n  if (e instanceof RangeError && e.message.includes('not available')) {\n    scaleViewport(xr.view(0)); // monoscopic fallback\n  } else {\n    throw e;\n  }\n}","preventionTips":["Never hard-code two views; query the view count per frame","Handle monoscopic immersive-ar sessions (single view)","Treat pose/views as per-frame data that can shrink or be null","Fall back to view 0 / default viewport when the requested view is absent"],"tags":["webxr","viewer-pose","index-out-of-range"],"backgroundTag":"xr-view-not-available","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}