{"id":"43eaf3bcfaa74180","repo":"jestjs/jest","slug":"unexpected-return-from-a-matcher-function-matcher","errorCode":null,"errorMessage":"Unexpected return from a matcher function.\nMatcher functions should return an object in the following format:\n  {message?: string | function, pass: boolean}\n'${matcherUtils.stringify(result)}' was returned","messagePattern":"Unexpected return from a matcher function\\.\nMatcher functions should return an object in the following format:\n  (.+?)\n'(.+?)' was returned","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/expect/src/index.ts","lineNumber":430,"sourceCode":"  stringMatching: stringNotMatching,\n};\n\nexpect.arrayContaining = arrayContaining;\nexpect.arrayOf = arrayOf;\nexpect.closeTo = closeTo;\nexpect.objectContaining = objectContaining;\nexpect.stringContaining = stringContaining;\nexpect.stringMatching = stringMatching;\n\nconst _validateResult = (result: any) => {\n  if (\n    typeof result !== 'object' ||\n    typeof result.pass !== 'boolean' ||\n    (result.message &&\n      typeof result.message !== 'string' &&\n      typeof result.message !== 'function')\n  ) {\n    throw new Error(\n      'Unexpected return from a matcher function.\\n' +\n        'Matcher functions should ' +\n        'return an object in the following format:\\n' +\n        '  {message?: string | function, pass: boolean}\\n' +\n        `'${matcherUtils.stringify(result)}' was returned`,\n    );\n  }\n};\n\nfunction assertions(expected: number): void {\n  const error = new ErrorWithStack(undefined, assertions);\n\n  setState({\n    expectedAssertionsNumber: expected,\n    expectedAssertionsNumberError: error,\n  });\n}\nfunction hasAssertions(...args: Array<unknown>): void {","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/jestjs/jest/blob/f49721c78e195558b40913977c9230f5b7f559d8/packages/expect/src/index.ts#L412-L448","documentation":"_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.","triggerScenarios":"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).","commonSituations":"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.","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)."],"exampleFix":"// before\nexpect.extend({\n  toBeEven(received) {\n    return received % 2 === 0; // wrong: boolean, not result object\n  },\n});\n\n// after\nexpect.extend({\n  toBeEven(received) {\n    const pass = received % 2 === 0;\n    return {\n      pass,\n      message: () => `expected ${received} ${this.isNot ? 'not ' : ''}to be even`,\n    };\n  },\n});","handlingStrategy":"validation","validationCode":"function assertMatcherResult(result: unknown): asserts result is { pass: boolean; message?: () => string } {\n  if (!result || typeof result !== 'object' || typeof (result as any).pass !== 'boolean') {\n    throw new Error('matcher must return { pass: boolean, message?: () => string }');\n  }\n}\n// inside the custom matcher, before returning:\nassertMatcherResult(result);\nreturn result;","typeGuard":"function isMatcherResult(x: unknown): x is { pass: boolean; message?: (() => string) | string } {\n  return typeof x === 'object' && x !== null && typeof (x as any).pass === 'boolean';\n}","tryCatchPattern":"// _validateResult throws inside the dispatcher; fix the custom matcher's return shape rather than catching","preventionTips":["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."],"tags":["expect","custom-matcher","expect-extend","validation"],"analyzedSha":"f49721c78e195558b40913977c9230f5b7f559d8","analyzedAt":"2026-08-03T20:16:28.571Z","schemaVersion":2}