jestjs/jest · error · Error
Unexpected return from a matcher function. Matcher…
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
Every matcher (built-in or from expect.extend) must return an object shaped like {pass: boolean, message?: string | (() => string)}. _validateResult runs after each matcher call and throws an Error if the return is missing, not an object, lacks a boolean `pass`, or has a `message` of the wrong type. This protects the dispatcher and diff renderer from malformed matcher output.
Solutions
- Ensure your matcher returns {pass: boolean, message: () => string} on every code path, including early returns.
- If using an arrow expression body, wrap the body in a block with an explicit return, or return the object literal directly.
- Use jest-matcher-utils' matcherHint/printExpected/printReceived to build the message thunk, and confirm `message` is a function (preferred) or string.
Example fix
// before
expect.extend({
toBeWithin(received, floor, ceil) {
if (received >= floor && received <= ceil) return true; // WRONG: boolean
return false;
},
});
// after
expect.extend({
toBeWithin(received, floor, ceil) {
const pass = received >= floor && received <= ceil;
return {
pass,
message: () =>
`expected ${received} to be within [${floor}, ${ceil}]`,
};
},
}); Defensive patterns
Strategy: validation
Validate before calling
// Validate a matcher's return shape before registering it.
function isValidMatcherResult(r) {
return (
r != null &&
typeof r === 'object' &&
typeof r.pass === 'boolean' &&
(r.message === undefined ||
typeof r.message === 'string' ||
typeof r.message === 'function')
);
}
// In a dev wrapper around expect.extend, sanity-check each matcher on a sample input. Type guard
interface MatcherResult { pass: boolean; message?: string | (() => string); }
function isMatcherResult(v: unknown): v is MatcherResult {
if (!v || typeof v !== 'object') return false;
const r = v as Record<string, unknown>;
if (typeof r.pass !== 'boolean') return false;
const m = r.message;
return m === undefined || typeof m === 'string' || typeof m === 'function';
} Try / catch
try {
const result = customMatcher.call(ctx, received, ...args);
if (!isMatcherResult(result)) {
throw new Error(`Custom matcher returned an invalid shape: ${JSON.stringify(result)}`);
}
} catch (e) {
// report the matcher name and received args to fix the return shape
} Prevention
- Always return {pass, message: () => string} from custom matchers on every path.
- Use a block body with explicit return statements to avoid implicit undefined.
- Write a tiny unit test for each custom matcher that asserts the result shape.
When it happens
Trigger: Writing a custom matcher (via expect.extend) that returns undefined, a boolean, or an object without a `pass` field; or a matcher that returns {message: 123} (non-string/non-function message). The error shows the actual returned value via stringify to aid debugging.
Common situations: Forgetting `return` in a matcher arrow function so it returns undefined; returning `true/false` instead of `{pass, message}`; a matcher whose early-return path omits the message; refactoring a matcher and dropping the return shape.
Related errors
- expect.extend: ` ` is not a valid matcher. Must be a…
- any() expects to be passed a constructor function. Please…
- expect.customEqualityTesters: Must be set to an array of…
- Expect takes at most one argument.
- Expected is not a string
AI-assisted analysis of jestjs/jest@8e6d128e4a (2026-08-10).
Data as JSON: /api/errors/43eaf3bcfaa74180.
Report an issue: GitHub.
Appendix: 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 8e6d128e4a)