jestjs/jest · error · TypeError
Invalid second argument, ${fn}. It must be a callback functi
Error message
Invalid second argument, ${fn}. It must be a callback function. What it means
it()/test()'s second argument must be a function. Env.ts:559-562 throws a TypeError when fn is defined but not a function (e.g. an object, array, config, or value). The interpolated fn in the message shows exactly what was passed.
Source
Thrown at packages/jest-jasmine2/src/jasmine/Env.ts:560
reporter.specDone(result);
}
function specStarted(spec: Spec) {
currentSpec = spec;
defaultResourcesForRunnable(spec.id, suite.id);
reporter.specStarted(spec.result);
}
};
this.it = function (description, fn, timeout) {
description = convertDescriptorToString(description);
if (fn === undefined) {
throw new Error(
'Missing second argument. It must be a callback function. Perhaps you want to use `test.todo` for a test placeholder.',
);
}
if (typeof fn !== 'function') {
throw new TypeError(
`Invalid second argument, ${fn}. It must be a callback function.`,
);
}
const spec = specFactory(
description,
fn,
currentDeclarationSuite,
timeout,
);
if (currentDeclarationSuite.markedPending) {
spec.pend();
}
// When a test is defined inside another, jasmine will not run it.
// This check throws an error to warn the user about the edge-case.
if (currentSpec !== null) {
throw new Error(
`Tests cannot be nested. Test "${spec.description}" cannot run because it is nested within "${currentSpec.description}".`,View on GitHub (pinned to f49721c78e)
Solutions
- Pass a function: it('name', () => { ... }).
- Use the interpolated value in the error to identify the wrong binding and fix it.
- For options like timeout, pass them as the third argument: it('name', fn, 1000).
Example fix
// before — options object passed as body
it('calculates tax', { timeout: 1000 });
// after — function body, timeout as 3rd arg
it('calculates tax', () => { expect(calc(10)).toBe(1); }, 1000); Defensive patterns
Strategy: type-guard
Validate before calling
function assertItFn(fn: unknown) {
if (typeof fn !== 'function') throw new TypeError('it callback must be a function');
} Type guard
function isFn(v: unknown): v is Function { return typeof v === 'function'; }
if (!isFn(fn)) throw new TypeError('it needs a function callback'); Prevention
- Pass options like timeout as the 3rd argument, never as the 2nd.
- Type test helpers so a non-function it body is a compile error.
When it happens
Trigger: Calling `it('name', { skip: true })`, `it('name', 42)`, or otherwise passing a non-function. The `typeof fn !== 'function'` check at Env.ts:559 fires the TypeError at line 560.
Common situations: Passing an options object meant for a custom wrapper; destructuring bug forwarding the wrong value; refactoring a parametrized test incorrectly.
Related errors
- Missing second argument. It must be a callback function. Per
- Invalid second argument, ${specDefinitions}. It must be a ca
- Tests cannot be nested. Test "${spec.description}" cannot ru
- Todo must be called with only a description.
- Missing second argument. It must be a callback function.
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/30c29fee3aded893.json.
Report an issue: GitHub.