liabru/matter-js · error · Error

Matter.Runner: missing required global…

Error message

Matter.Runner: missing required global window.cancelAnimationFrame.

What it means

Runner._cancelNextFrame cancels a scheduled frame using window.cancelAnimationFrame, which must exist to stop the runner loop safely. When window or cancelAnimationFrame is unavailable (Node, Worker, jsdom), Runner.stop()/pause cannot cancel the pending callback and throws. It is the teardown counterpart of error 0.

Solutions

  1. Ensure the environment provides both requestAnimationFrame AND cancelAnimationFrame on window.
  2. Polyfill both: window.cancelAnimationFrame = id => clearTimeout(id) alongside the RAF polyfill.
  3. Store the frameRequestId returned by Runner.run and call window.cancelAnimationFrame yourself in a compatible environment.
  4. In browsers, this should never occur — verify code is not accidentally running in a Worker context.

Example fix

// before (Node.js test)
Matter.Runner.stop(runner); // throws
// after
window.cancelAnimationFrame = id => clearTimeout(id); // polyfill first
Matter.Runner.stop(runner);
Defensive patterns

Strategy: fallback

Validate before calling

if (typeof window === 'undefined' || typeof window.cancelAnimationFrame !== 'function') {
  globalThis.window = globalThis.window || {};
  window.cancelAnimationFrame = window.cancelAnimationFrame || (id => clearTimeout(id));
}

Type guard

function canCancelRaf(env) {
  return typeof env !== 'undefined' && env !== null && typeof env.cancelAnimationFrame === 'function';
}

Try / catch

try {
  Matter.Runner.stop(runner);
} catch (e) {
  if (String(e.message).includes('cancelAnimationFrame') && runner.frameRequestId) {
    clearTimeout(runner.frameRequestId);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Calling Runner.stop(runner) or Runner.pause(runner) in an environment lacking window.cancelAnimationFrame — typically Node, Web Worker, or jsdom tests.

Common situations: Stopping a runner in server-side code after a polyfilled start; cleaning up tests without a full RAF polyfill (started but cannot cancel).

Related errors


AI-assisted analysis of liabru/matter-js@acb99b6f87 (2026-09-02). Data as JSON: /api/errors/b94ba01bbc7b292d. Report an issue: GitHub.

Appendix: source

Thrown at src/core/Runner.js:250

            runner.frameRequestId = window.requestAnimationFrame(callback);
        } else {
            throw new Error('Matter.Runner: missing required global window.requestAnimationFrame.');
        }

        return runner.frameRequestId;
    };

    /**
     * Cancels the last callback scheduled by `Runner._onNextFrame` on this `runner`.
     * @private
     * @method _cancelNextFrame
     * @param {runner} runner
     */
    Runner._cancelNextFrame = function(runner) {
        if (typeof window !== 'undefined' && window.cancelAnimationFrame) {
            window.cancelAnimationFrame(runner.frameRequestId);
        } else {
            throw new Error('Matter.Runner: missing required global window.cancelAnimationFrame.');
        }
    };

    /**
     * Returns the mean of the given numbers.
     * @method _mean
     * @private
     * @param {Number[]} values
     * @return {Number} the mean of given values.
     */
    var _mean = function(values) {
        var result = 0,
            valuesLength = values.length;

        for (var i = 0; i < valuesLength; i += 1) {
            result += values[i];
        }

View on GitHub (pinned to acb99b6f87)