denoland/deno · error · TypeError
after() requires a function
Error message
after() requires a function
What it means
t.after(fn) on the node:test context registers a teardown hook that runs once after this test's subtests complete. Like the other context hooks it only stores functions; a non-function argument throws TypeError 'after() requires a function'.
Source
Thrown at ext/node/polyfills/testing.ts:1613
this.#subtestPromises.length,
);
for (const p of new SafeArrayIterator(promises)) {
try {
await p;
} catch { /* failures already reported through the subtest's own step */ }
}
}
before(fn, _options) {
if (typeof fn !== "function") {
throw new TypeError("before() requires a function");
}
ArrayPrototypePush(this.#beforeHooks, fn);
}
after(fn, _options) {
if (typeof fn !== "function") {
throw new TypeError("after() requires a function");
}
ArrayPrototypePush(this.#afterHooks, fn);
}
beforeEach(fn, _options) {
if (typeof fn !== "function") {
throw new TypeError("beforeEach() requires a function");
}
ArrayPrototypePush(this.#beforeEachHooks, fn);
}
afterEach(fn, _options) {
if (typeof fn !== "function") {
throw new TypeError("afterEach() requires a function");
}
ArrayPrototypePush(this.#afterEachHooks, fn);
}
View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Pass the function reference: t.after(closeDb)
- Wrap immediate calls: t.after(() => closeDb()) only if you truly need to call it later
- Ensure dynamic hook registration checks typeof fn === 'function' first
Example fix
// before t.after(disposeHandles()); // after t.after(disposeHandles);
Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof teardown !== 'function') {
throw new TypeError(`t.after: expected function, got ${typeof teardown}`);
}
t.after(teardown); Type guard
const isHookFn = (fn) => typeof fn === 'function';
if (isHookFn(teardown)) {
t.after(teardown);
} Prevention
- Reference cleanup functions; do not call them at registration time
- Wrap only when deferral is intended: t.after(() => close())
- Guard optional teardowns: if (teardown) t.after(teardown)
When it happens
Trigger: t.after() with no argument; t.after(cleanupDb()) passing the Promise returned by an immediate call instead of the function; passing an options object or string.
Common situations: Invoking the cleanup instead of referencing it (a classic with arrow-less refactors); copy-paste from a hook that took a name string first.
Related errors
- before() requires a function
- beforeEach() requires a function
- afterEach() requires a function
- before() requires a function argument
- after() requires a function argument
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/dedfcdb70b6a59be.
Report an issue: GitHub.