denoland/deno · error · TypeError
before() requires a function
Error message
before() requires a function
What it means
The node:test context exposes t.before(fn) to register a hook that runs once before this test's subtests. It stores fn in an internal hooks array and requires it to be a function; anything else (including undefined or the result of calling a function) throws TypeError 'before() requires a function'.
Source
Thrown at ext/node/polyfills/testing.ts:1606
// which are commonly not awaited (e.g. fastify's suites), still run to
// completion before the parent test settles.
async _drainSubtests() {
if (this.#subtestPromises.length === 0) return;
const promises = ArrayPrototypeSplice(
this.#subtestPromises,
0,
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);
}
View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Pass the function reference: t.before(initDb)
- Keep argument order (fn, options) — options are the second parameter
- For async setup, pass the async function itself so the runner can await it
Example fix
// before
t.before({ timeout: 1000 }, connectDb);
// after
t.before(connectDb, { timeout: 1000 }); Defensive patterns
Strategy: type-guard
Validate before calling
if (typeof hook !== 'function') {
throw new TypeError(`t.before: expected function, got ${typeof hook}`);
}
t.before(hook, { timeout: 1000 }); Type guard
const isHookFn = (fn) => typeof fn === 'function';
if (isHookFn(setup)) {
t.before(setup);
} Prevention
- Pass the function reference, never its invocation result
- Hook signature is (fn, options) — options come second
- For async setup, pass the async function itself so the runner awaits it
- Guard config-driven hook wiring with a typeof check
When it happens
Trigger: t.before() with no argument; t.before({ timeout: 1000 }, hook) with arguments in the wrong order (signature is (fn, options)); t.before(initDb()) passing a Promise instead of the function.
Common situations: Calling the setup function instead of referencing it; options-first habit carried over from other hook APIs; wiring hooks from config where the value can be undefined.
Related errors
- after() 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/964b316731e0b9c2.
Report an issue: GitHub.