avajs/ava · error · TypeError
Expected a function
Error message
Expected a function
What it means
t.teardown(callback) registers a function to run when the test finishes. AVA requires a function; passing any non-callable value throws this TypeError immediately. Note the related guard: t.teardown() called during teardown records a different error instead.
Source
Thrown at lib/test.js:474
clearTimeout() {
nowAndTimers.clearTimeout(this.timeoutTimer);
this.timeoutTimer = null;
}
addTeardown(callback) {
if (this.isHook) {
this.saveFirstError(new Error('`t.teardown()` is not allowed in hooks'));
return;
}
if (this.finishing) {
this.saveFirstError(new Error('`t.teardown()` cannot be used during teardown'));
return;
}
if (typeof callback !== 'function') {
throw new TypeError('Expected a function');
}
this.teardowns.push(callback);
}
async runTeardowns() {
const teardowns = this.teardowns.toReversed();
for (const teardown of teardowns) {
try {
await teardown(); // eslint-disable-line no-await-in-loop
} catch (error) {
this.saveFirstError(error);
}
}
}
verifyPlan() {View on GitHub (pinned to bbfd946322)
Solutions
- Pass the function reference, don't call it: t.teardown(cleanup) not t.teardown(cleanup()).
- Verify the callback is defined at call time (imports, hoisting).
- Prefer t.after(fn) for hooks that can be async and receive context; keep t.teardown for plain functions.
Example fix
// before t.teardown(stopServer()); // passes return value // after t.teardown(stopServer); // passes the function itself
Defensive patterns
Strategy: validation
Validate before calling
if (typeof callback !== 'function') throw new TypeError('t.teardown() expects a function, got: ' + typeof callback);
t.teardown(callback); Type guard
const isCallable = (v) => typeof v === 'function';
Try / catch
try {
t.teardown(callback);
} catch (err) {
if (err instanceof TypeError && err.message === 'Expected a function') {
throw new Error('t.teardown() called without a function — did you invoke the callback instead of passing it?');
}
throw err;
} Prevention
- Pass the function reference: t.teardown(stop), not t.teardown(stop())
- Prefer t.after() for async or context-aware hooks
- Verify imports/definitions of teardown callbacks after refactors
When it happens
Trigger: t.teardown(myVar) where myVar is undefined (bad import); t.teardown(await cleanup()) which passes the result instead of the function; passing a promise or a boolean flag instead of a callback.
Common situations: Confusing t.teardown with t.after (t.after accepts hooks the same way, but the value passed may be the result of an eagerly-invoked function); calling cleanup() instead of passing cleanup; typos in import names.
Related errors
- Expected an implementation.
- Expected an implementation. Use `test.todo()` for tests with
- Test & hook titles must be strings
- Tests must have a title
- `t.try()` titles must be strings
AI-assisted analysis of avajs/ava@bbfd946322 (2026-09-02).
Data as JSON: /api/errors/5f3d82dbc8b1cccd.
Report an issue: GitHub.