jestjs/jest · error · Error
received value must be a mock function
Error message
received value must be a mock function
What it means
Thrown by `ensureMock` (spyMatchers.ts:1282), invoked from `toHaveReturned`, `toHaveReturnedTimes`, `toHaveReturnedWith`, `toHaveLastReturnedWith`, and `toHaveNthReturnedWith`. It fires when the received value is not a Jest mock function (`_isMockFunction === true`). These matchers specifically need `received.mock.results` (return values), which only Jest mocks carry — a Jasmine spy exposes `.calls` but not `.mock.results`, so `ensureMock` is stricter than `ensureMockOrSpy`.
Source
Thrown at packages/expect/src/spyMatchers.ts:1289
if (!isMock(received) && !isSpy(received)) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, expectedArgument, options),
`${RECEIVED_COLOR('received')} value must be a mock or spy function`,
printWithType('Received', received, printReceived),
),
);
}
};
const ensureMock = (
received: any,
matcherName: string,
expectedArgument: string,
options: MatcherHintOptions,
) => {
if (!isMock(received)) {
throw new Error(
matcherErrorMessage(
matcherHint(matcherName, undefined, expectedArgument, options),
`${RECEIVED_COLOR('received')} value must be a mock function`,
printWithType('Received', received, printReceived),
),
);
}
};
export default spyMatchers;
View on GitHub (pinned to f49721c78e)
Solutions
- Use `jest.fn()` to create the mock so `.mock.results` is populated.
- If you only need call assertions (not return values), switch to `toHaveBeenCalled*` matchers which accept spies too.
- Log `received._isMockFunction` — must be `true` for `toHaveReturned*`.
- Ensure you are not passing a different framework's spy (sinon/vitest).
Example fix
// before
const fn = sinon.fake(); // not a Jest mock
run(fn);
expect(fn).toHaveReturnedWith('ok');
// after
const fn = jest.fn();
run(fn);
expect(fn).toHaveReturnedWith('ok'); Defensive patterns
Strategy: type-guard
Validate before calling
if (received == null || received._isMockFunction !== true) {
throw new Error('received must be a jest.fn() mock (spies without .mock.results are not supported here)');
}
expect(received).toHaveReturned(); Type guard
const isJestMock = (v: unknown): v is {mock: {results: Array<unknown>; calls: Array<unknown>}; getMockName: () => string} =>
v != null && (v as any)._isMockFunction === true; Try / catch
try {
expect(received).toHaveReturnedWith(value);
} catch (e) {
if (e instanceof Error && /must be a mock function/.test(e.message)) {
console.error('received is not a jest.fn() mock:', received);
}
throw e;
} Prevention
- Use `jest.fn()` so `.mock.results` is populated for return assertions.
- For spies or non-Jest fakes, switch to `toHaveBeenCalled*` matchers.
- Confirm `received._isMockFunction === true` before `toHaveReturned*` calls.
When it happens
Trigger: Calling `expect(plainFn).toHaveReturnedWith(value)` on a non-mock function; `expect(spy).toHaveReturned()` where `spy` is a Jasmine-style spy without a `.mock` property; `expect(obj.method).toHaveReturned()` on an unspied method; using a non-Jest fake (sinon stub, vitest spy) that doesn't expose `_isMockFunction`.
Common situations: Spying with a library other than Jest; forgetting `jest.fn()` around a callback; the function under test is the real implementation; using `toHaveReturned*` on something that was set up with `jest.spyOn` but where the return-tracking mock shape is missing (rare — `jest.spyOn` does produce a mock).
Related errors
- received value must be a mock or spy function
- ${expectedArgument} must be a positive integer
- expected value must be a number
- received value must be a number
- expected value must be a function
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/69d4e960a783ce2f.json.
Report an issue: GitHub.