{"record":{"id":"5f3d82dbc8b1cccd","repo":"avajs/ava","slug":"expected-a-function","errorCode":null,"errorMessage":"Expected a function","messagePattern":"Expected a function","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/test.js","lineNumber":474,"sourceCode":"\n\tclearTimeout() {\n\t\tnowAndTimers.clearTimeout(this.timeoutTimer);\n\t\tthis.timeoutTimer = null;\n\t}\n\n\taddTeardown(callback) {\n\t\tif (this.isHook) {\n\t\t\tthis.saveFirstError(new Error('`t.teardown()` is not allowed in hooks'));\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.finishing) {\n\t\t\tthis.saveFirstError(new Error('`t.teardown()` cannot be used during teardown'));\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Expected a function');\n\t\t}\n\n\t\tthis.teardowns.push(callback);\n\t}\n\n\tasync runTeardowns() {\n\t\tconst teardowns = this.teardowns.toReversed();\n\n\t\tfor (const teardown of teardowns) {\n\t\t\ttry {\n\t\t\t\tawait teardown(); // eslint-disable-line no-await-in-loop\n\t\t\t} catch (error) {\n\t\t\t\tthis.saveFirstError(error);\n\t\t\t}\n\t\t}\n\t}\n\n\tverifyPlan() {","sourceCodeStart":456,"sourceCodeEnd":492,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/test.js#L456-L492","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nt.teardown(stopServer()); // passes return value\n\n// after\nt.teardown(stopServer); // passes the function itself","handlingStrategy":"validation","validationCode":"if (typeof callback !== 'function') throw new TypeError('t.teardown() expects a function, got: ' + typeof callback);\nt.teardown(callback);","typeGuard":"const isCallable = (v) => typeof v === 'function';","tryCatchPattern":"try {\n  t.teardown(callback);\n} catch (err) {\n  if (err instanceof TypeError && err.message === 'Expected a function') {\n    throw new Error('t.teardown() called without a function — did you invoke the callback instead of passing it?');\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["ava","t-teardown","typeerror","missing-argument"],"backgroundTag":"expected-function-argument","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}