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
- Move tracker.calls() registration into normal setup (module load / test start), never into exit or teardown hooks.
- In exit handlers, only call tracker.verify()/report() on functions registered earlier — those remain allowed.
- 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
- Register all tracked functions during setup, before any exit handler can run.
- Never create mocks inside 'exit'/'beforeExit' listeners or signal-driven shutdown paths.
- Limit exit handlers to verify()/report() on already-registered functions.
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
- ERR_INVALID_ARG_VALUE
- ERR_ASSERTION
- ERR_ASSERTION
- ERR_INVALID_OBJECT_DEFINE_PROPERTY
- ERR_CONSTRUCT_CALL_REQUIRED
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/bc4e5ce9095d6c11.
Report an issue: GitHub.