aframevr / aframevr/aframe

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

Open Beginner friendly
#5,844 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
17.6k
Forks
4.4k
PR merge metrics
No merged PRs in 30d

Description

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:

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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in the render-loop implementation around stopRendering in aframe.js, then reproduce repeated WebXR session exits and re-entries using the A-Painter scenario described. Confirm that session transitions no longer throw the reported cancelAnimationFrame error and that rendering continues normally.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
computer-graphics, web-dev
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.