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

  1. Ensure your matcher returns {pass: boolean, message: () => string} on every code path, including early returns.
  2. If using an arrow expression body, wrap the body in a block with an explicit return, or return the object literal directly.
  3. 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

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


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)