denoland/deno · error · Error

ERR_UNAVAILABLE_DURING_EXIT

ERR_UNAVAILABLE_DURING_EXIT

Error message

Cannot call function in process exit handler

What it means

CallTracker.calls() refuses to register new tracked functions once the process has begun exiting (process._exiting is set when the 'exit' event is imminent). Any tracker.calls(...) executed in that window throws ERR_UNAVAILABLE_DURING_EXIT, because assertions registered after exit could never be verified.

Source

Thrown at ext/node/polyfills/internal/assert/calltracker.js:112

  }

  reset(tracked) {
    if (tracked === undefined) {
      SetPrototypeForEach(this.#callChecks, (check) => check.reset());
      return;
    }

    this.#getTrackedFunction(tracked).reset();
  }

  getCalls(tracked) {
    return this.#getTrackedFunction(tracked).getCalls();
  }

  calls(fn, expected = 1) {
    // deno-lint-ignore no-process-global
    if (process._exiting) {
      throw new ERR_UNAVAILABLE_DURING_EXIT();
    }
    if (typeof fn === "number") {
      expected = fn;
      fn = noop;
    } else if (fn === undefined) {
      fn = noop;
    }

    validateUint32(expected, "expected", true);

    const context = new CallTrackerContext({
      expected,
      // eslint-disable-next-line no-restricted-syntax
      stackTrace: new Error(),
      name: fn.name || "calls",
    });
    const tracked = new Proxy(fn, {
      __proto__: null,

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Move tracker.calls() registration into normal setup (module load / test start), never into exit or teardown hooks.
  2. In exit handlers, only call tracker.verify()/report() on functions registered earlier — those remain allowed.
  3. Restructure shutdown code so no new tracking is created after exit begins.

Example fix

// before
process.on('exit', () => {
  const t = tracker.calls(cleanup); // ERR_UNAVAILABLE_DURING_EXIT
  cleanup();
  tracker.verify();
});

// after
const t = tracker.calls(cleanup);
process.on('exit', () => {
  cleanup();
  tracker.verify();
});
Defensive patterns

Strategy: validation

Validate before calling

function safeCalls(tracker, fn, expected = 1) {
  if (process._exiting) {
    throw new Error('cannot register tracked functions during process exit');
  }
  return tracker.calls(fn, expected);
}

Prevention

When it happens

Trigger: tracker.calls(fn) inside a process.on('exit', ...) handler; registering mocks from teardown code that runs during shutdown; late-arriving async work that wraps functions after exit has started.

Common situations: Test harnesses installing exit-time cleanup that also sets up mocks; signal handlers (SIGTERM/SIGINT) that lazily instrument code during forced shutdown.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/bc4e5ce9095d6c11. Report an issue: GitHub.