jestjs/jest · error · Error
Unexpected return from a matcher function. Matcher functions
Error message
Unexpected return from a matcher function.
Matcher functions should return an object in the following format:
{message?: string | function, pass: boolean}
'${matcherUtils.stringify(result)}' was returned What it means
_validateResult inspects the return value of every matcher (built-in and custom) and requires an object with `pass: boolean` and an optional `message` that is a string or function. If a custom matcher returns a boolean, undefined, a Promise, or an object missing `pass`, this error is thrown with the stringified result so you can see what went wrong. It protects the dispatcher from continuing on garbage.
Source
Thrown at packages/expect/src/index.ts:430
stringMatching: stringNotMatching,
};
expect.arrayContaining = arrayContaining;
expect.arrayOf = arrayOf;
expect.closeTo = closeTo;
expect.objectContaining = objectContaining;
expect.stringContaining = stringContaining;
expect.stringMatching = stringMatching;
const _validateResult = (result: any) => {
if (
typeof result !== 'object' ||
typeof result.pass !== 'boolean' ||
(result.message &&
typeof result.message !== 'string' &&
typeof result.message !== 'function')
) {
throw new Error(
'Unexpected return from a matcher function.\n' +
'Matcher functions should ' +
'return an object in the following format:\n' +
' {message?: string | function, pass: boolean}\n' +
`'${matcherUtils.stringify(result)}' was returned`,
);
}
};
function assertions(expected: number): void {
const error = new ErrorWithStack(undefined, assertions);
setState({
expectedAssertionsNumber: expected,
expectedAssertionsNumberError: error,
});
}
function hasAssertions(...args: Array<unknown>): void {View on GitHub (pinned to f49721c78e)
Solutions
- Return `{ pass: boolean, message: () => string }` from the custom matcher function.
- Use `this.isNot` to phrase the message correctly for both pass/fail branches.
- If you need async work, return a Promise that resolves to the result object (and ensure intermediate returns also conform).
Example fix
// before
expect.extend({
toBeEven(received) {
return received % 2 === 0; // wrong: boolean, not result object
},
});
// after
expect.extend({
toBeEven(received) {
const pass = received % 2 === 0;
return {
pass,
message: () => `expected ${received} ${this.isNot ? 'not ' : ''}to be even`,
};
},
}); Defensive patterns
Strategy: validation
Validate before calling
function assertMatcherResult(result: unknown): asserts result is { pass: boolean; message?: () => string } {
if (!result || typeof result !== 'object' || typeof (result as any).pass !== 'boolean') {
throw new Error('matcher must return { pass: boolean, message?: () => string }');
}
}
// inside the custom matcher, before returning:
assertMatcherResult(result);
return result; Type guard
function isMatcherResult(x: unknown): x is { pass: boolean; message?: (() => string) | string } {
return typeof x === 'object' && x !== null && typeof (x as any).pass === 'boolean';
} Try / catch
// _validateResult throws inside the dispatcher; fix the custom matcher's return shape rather than catching
Prevention
- Always return { pass, message: () => string } from custom matchers.
- Use a shared helper to build the result object so the shape is enforced.
- Write a unit test for each custom matcher that asserts it returns the correct shape.
When it happens
Trigger: Writing a custom matcher in expect.extend that returns `true`/`false` directly, returns nothing (undefined), returns `{ message: '...' }` without `pass`, or returns a Promise (sync matchers must return the result object directly — async matchers are a separate path).
Common situations: First-time custom matcher authors forgetting the `{pass, message}` shape; refactoring a matcher and dropping the return; returning a chained ternary that evaluates to undefined; copying a matcher that threw instead of returned.
Related errors
- expect.extend: `${key}` is not a valid matcher. Must be a fu
- any() expects to be passed a constructor function. Please pa
- Expected is not a string
- Expected is not a String or a RegExp
- Expected is not a Number
AI-assisted analysis of jestjs/jest@f49721c78e (2026-08-03).
Data as JSON: /data/errors/43eaf3bcfaa74180.json.
Report an issue: GitHub.