{"record":{"id":"e3929dad7fe4c93f","repo":"avajs/ava","slug":"t-throws-must-be-called-with-a-function","errorCode":null,"errorMessage":"`t.throws()` must be called with a function","messagePattern":"`t\\.throws\\(\\)` must be called with a function","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"lib/assert.js","lineNumber":407,"sourceCode":"\n\t\t\tconst actualDescriptor = result.actual ?? concordance.describe(comparable, concordanceOptions);\n\t\t\tconst expectedDescriptor = result.expected ?? concordance.describe(selector, concordanceOptions);\n\t\t\tthrow fail(new AssertionError(message, {\n\t\t\t\tassertion: 't.like()',\n\t\t\t\tformattedDetails: [formatDescriptorDiff(actualDescriptor, expectedDescriptor)],\n\t\t\t}));\n\t\t});\n\n\t\tthis.throws = withSkip((...args) => {\n\t\t\t// Since arrow functions do not support 'arguments', we are using rest\n\t\t\t// operator, so we can determine the total number of arguments passed\n\t\t\t// to the function.\n\t\t\tlet [fn, expectations, message] = args;\n\n\t\t\tassertMessage(message, 't.throws()');\n\n\t\t\tif (typeof fn !== 'function') {\n\t\t\t\tthrow fail(new AssertionError('`t.throws()` must be called with a function', {\n\t\t\t\t\tassertion: 't.throws()',\n\t\t\t\t\timproperUsage: {assertion: 'throws'},\n\t\t\t\t\tformattedDetails: [formatWithLabel('Called with:', fn)],\n\t\t\t\t}));\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\texpectations = validateExpectations('t.throws()', expectations, args.length, experiments);\n\t\t\t} catch (error) {\n\t\t\t\tthrow fail(error);\n\t\t\t}\n\n\t\t\tlet retval;\n\t\t\tlet threw = false;\n\t\t\tlet actual = null;\n\t\t\ttry {\n\t\t\t\tretval = fn();\n\t\t\t\tif (isPromise(retval)) {","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/avajs/ava/blob/bbfd946322fdeca2b547a691d947fb4e18c0c67f/lib/assert.js#L389-L425","documentation":"AVA throws this fixed usage error when t.throws() is invoked with a first argument that is not a function. t.throws() synchronously invokes its argument to observe a throw, so anything other than a callable is improper usage; the error is flagged with improperUsage so AVA can point at a mistake in the test rather than a failure of the code under test.","triggerScenarios":"t.throws(undefined), t.throws(await asyncFn()), t.throws(promise) — passing the result of an async call, a promise, or forgetting to pass a thunk, e.g. t.throws(fs.readFileSync('nope')) instead of () => fs.readFileSync('nope').","commonSituations":"Calling the function eagerly instead of wrapping it in an arrow function; migrating from t.throwsAsync and passing a promise; typo'd variable that is undefined at call time.","solutions":["Wrap the call in a function: t.throws(() => risky()).","If the code is asynchronous, switch to t.throwsAsync(() => riskyAsync()).","Check that the variable holding the function is actually defined and is a function."],"exampleFix":"// before\nt.throws(readConfig('missing.json'));\n// after\nt.throws(() => readConfig('missing.json'));","handlingStrategy":"type-guard","validationCode":"if (typeof fn !== 'function') throw new TypeError('t.throws() expects a function; got ' + typeof fn);","typeGuard":"const isCallable = (v) => typeof v === 'function';\nif (!isCallable(fn)) { /* fix before asserting */ }","tryCatchPattern":"try {\n  t.throws(fn, expectations);\n} catch (err) {\n  if (/must be called with a function/.test(err.message)) {\n    t.fail('Wrap the call in a thunk: t.throws(() => ...)');\n  } else { throw err; }\n}","preventionTips":["Always pass an arrow-function wrapper: t.throws(() => code()).","Never pass a promise or awaited result to t.throws — use t.throwsAsync for async code.","Check for undefined function variables before the assertion."],"tags":["assertion","ava","type-error","usage-error"],"backgroundTag":"assertion-requires-function","analyzedSha":"bbfd946322fdeca2b547a691d947fb4e18c0c67f","analyzedAt":"2026-09-02T01:24:43.834Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}