BabylonJS/Babylon.js · error

Restoring persistent anchors requires the anchor system to b

Error message

Restoring persistent anchors requires the anchor system to be attached

What it means

restorePersistentAnchorAsync resolves a persisted handle back into a tracked anchor, which requires an active, attached WebXR feature. If the anchor system is not currently attached to a session, the method cannot interact with the XRSession and throws this error before attempting the native restore. It is a state error, not a capability error.

Source

Thrown at packages/dev/core/src/XR/features/WebXRAnchorSystem.pure.ts:331

    public async requestPersistentHandleAsync(anchor: IWebXRAnchor): Promise<string> {
        const requestPersistentHandle = anchor.xrAnchor.requestPersistentHandle;
        if (!requestPersistentHandle) {
            throw new Error("Requesting persistent anchor handles is not supported in this environment/browser");
        }
        const handle = await requestPersistentHandle.call(anchor.xrAnchor);
        this._setPersistentHandle(anchor, handle);
        return handle;
    }

    /**
     * Restore a persistent anchor into the Babylon anchor lifecycle
     * @param handle The persistent anchor handle to restore
     * @returns A promise that resolves after the restored anchor is tracked by an XR frame
     * @throws If restoring persistent anchors is not supported by the current session
     */
    public async restorePersistentAnchorAsync(handle: string): Promise<IWebXRAnchor> {
        if (!this.attached) {
            throw new Error("Restoring persistent anchors requires the anchor system to be attached");
        }

        const session = this._xrSessionManager.session;
        const restorePersistentAnchor = session?.restorePersistentAnchor;
        if (!restorePersistentAnchor) {
            throw new Error("Restoring persistent anchors is not supported in this environment/browser");
        }

        const nativeAnchor = await restorePersistentAnchor.call(session, handle);
        if (!this.attached || this._xrSessionManager.session !== session) {
            nativeAnchor.delete();
            throw new Error("Persistent anchor restoration was interrupted before tracking began");
        }
        const existingAnchorIndex = this._findIndexInAnchorArray(nativeAnchor);
        if (existingAnchorIndex !== -1) {
            const existingAnchor = this._trackedAnchors[existingAnchorIndex];
            existingAnchor.persistentHandle = handle;
            return existingAnchor;

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Only call restore after the session is running and the anchor system is attached (e.g. after onXRSessionStarted)
  2. Check anchorSystem.attached before invoking
  3. Ensure the feature is enabled via the WebXR experience helper so attach happens automatically
  4. Wrap in try/catch and defer restoration until attach completes

Example fix

// before
await anchorSystem.restorePersistentAnchorAsync(handle);
// after
if (anchorSystem.attached) {
  await anchorSystem.restorePersistentAnchorAsync(handle);
} else {
  xrSessionManager.onXRSessionStarted.addOnce(() =>
    anchorSystem.restorePersistentAnchorAsync(handle)
  );
}
Defensive patterns

Strategy: validation

Validate before calling

if (!anchorSystem.attached) {
  throw new Error('attach the anchor system before restoring persistent anchors');
}

Type guard

function isAttached(s: WebXRAnchorSystem): boolean {
  return s.attached;
}

Try / catch

try {
  await anchorSystem.restorePersistentAnchorAsync(handle);
} catch (e) {
  if (/attached/.test((e as Error).message)) {
    xrSessionManager.onXRSessionStarted.addOnce(() => anchorSystem.restorePersistentAnchorAsync(handle));
  }
}

Prevention

When it happens

Trigger: Calling restorePersistentAnchorAsync(handle) (directly or through restorePersistentAnchorsAsync) on a WebXRAnchorSystem instance that has not been attached — e.g. before the XR session starts or after the feature detached/session ended.

Common situations: Restoring anchors during app startup before entering XR, session ended asynchronously while restore logic was still running, forgetting to add the anchor system feature to the experience helpers.

Related errors


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