denoland/deno · error · TypeError
after() requires a function argument
Error message
after() requires a function argument
What it means
The module-level after(fn) from node:test registers a one-time teardown hook (attached to the current TAP suite when in TAP mode, otherwise to the root hooks). Like before(), it validates its first argument is a function and throws TypeError 'after() requires a function argument' for anything else, including a called function's return value.
Source
Thrown at ext/node/polyfills/testing.ts:2171
ArrayPrototypePush(tapSuite.beforeAllHooks ??= [], fn);
return;
}
ArrayPrototypePush(rootBeforeHooks, fn);
// A bare top-level `before()` with no tests must still produce TAP
// output (`before` runs, then `TAP version 13`, then `1..0`).
scheduleTapRun();
return;
}
if (currentSuite) {
ArrayPrototypePush(currentSuite.beforeAllHooks, fn);
return;
}
ArrayPrototypePush(rootBeforeHooks, fn);
}
function after(fn, _options) {
if (typeof fn !== "function") {
throw new TypeError("after() requires a function argument");
}
if (isTapMode()) {
const tapSuite = getTapCurrentSuite();
if (tapSuite !== null) {
ArrayPrototypePush(tapSuite.afterAllHooks ??= [], fn);
return;
}
ArrayPrototypePush(rootAfterHooks, fn);
scheduleTapRun();
return;
}
if (currentSuite) {
ArrayPrototypePush(currentSuite.afterAllHooks, fn);
return;
}
ArrayPrototypePush(rootAfterHooks, fn);
}
View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Pass the function reference: after(closeDatabase)
- Guard optional hooks: if (teardown) after(teardown)
- Keep the (fn, options) argument order
Example fix
// before after(closePool()); // after after(closePool);
Defensive patterns
Strategy: type-guard
Validate before calling
import { after } from 'node:test';
if (typeof teardown !== 'function') {
throw new TypeError(`after: expected function, got ${typeof teardown}`);
}
after(teardown); Type guard
const isHookFn = (fn) => typeof fn === 'function';
if (isHookFn(teardown)) {
after(teardown);
} Prevention
- Reference teardown functions; do not invoke them at registration
- Keep the (fn, options) argument order
- Guard optional teardowns with an if before registering
When it happens
Trigger: after() with no argument; after(teardown()) passing a Promise; passing an options object in the fn position.
Common situations: Cleanup helpers invoked instead of referenced during refactors; optional teardowns that are undefined behind feature flags.
Related errors
- before() requires a function argument
- beforeEach() requires a function argument
- afterEach() requires a function argument
- before() requires a function
- after() requires a function
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/36ca60f8284e63c3.
Report an issue: GitHub.