#5844·aframe

Uncaught TypeError: Cannot read properties of null (reading 'cancelAnimationFrame') on session end

Author: XRDeltasCreated Jun 30, 2026Updated Jul 1, 2026

Description

When an A-Frame application ends an XR session and immediately re-enters, an Uncaught TypeError: Cannot read properties of null (reading 'cancelAnimationFrame') is thrown. This intermittently crashes the application during XR session lifecycle transitions.

The root cause is in A-Frame's render loop: cancelAnimationFrame is called with a null handle when the animation frame ID is cleaned up before the stop function reads it.

Environment

  • A-Frame version: Latest (affects A-Painter, A-Blast, and other A-Frame WebXR apps)
  • Browser: Chromium 124+ (mobile emulation triggers more frequently)
  • XR Mode: WebXR immersive-vr

Steps to Reproduce

  1. Open an A-Frame WebXR app (e.g., A-Painter)
  2. Enter VR (navigator.xr.requestSession('immersive-vr'))
  3. Perform interactions (select, aim)
  4. Exit VR (end the session)
  5. Re-enter VR immediately
  6. Repeat steps 4-5 multiple times

Expected Behavior

cancelAnimationFrame should gracefully handle a null handle, or the animation frame handle should never be null during the render loop.

Actual Behavior

Uncaught TypeError: Cannot read properties of null (reading 'cancelAnimationFrame') at stopRendering (aframe.js:XXXX)

Observed in ~15% of replay traces (3 out of 19 traces for A-Painter on mobile Chromium).

Root Cause

In A-Frame's render loop, the cancelAnimationFrame call does not guard against null:

javascript
let animFrameId = null;

function startRendering() {
    animFrameId = requestAnimationFrame(render);
}

function stopRendering() {
    cancelAnimationFrame(animFrameId);  // ← animFrameId can be null
    animFrameId = null;
}
Under rapid XR session switching, a race condition exists where animFrameId is set to null before stopRendering reads it.

Proposed Fix
Add a null guard:
function stopRendering() {
    if (animFrameId != null) {
        cancelAnimationFrame(animFrameId);
    }
    animFrameId = null;
}
Additional Context
This bug was discovered via an automated cross-host replay system (WebXRBench) that replays WebXR interaction traces across different browser configurations. The error was captured in 192 divergence instances across 17 traces and 2 A-Frame apps.

Severity: Medium — intermittent but causes JavaScript execution interruption that can manifest as rendering glitches or state corruption.