{"record":{"id":"b57192d1b271104e","repo":"vitest-dev/vitest","slug":"asymmetric-matcher-val-constructor-name-does-no","errorCode":null,"errorMessage":"Asymmetric matcher ${val.constructor.name} does not implement toAsymmetricMatcher()","messagePattern":"Asymmetric matcher (.+?) does not implement toAsymmetricMatcher\\(\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/pretty-format/src/plugins/AsymmetricMatcher.ts","lineNumber":84,"sourceCode":"      stringedValue\n      + SPACE\n      + printer(val.sample, config, indentation, depth, refs)\n    )\n  }\n\n  if (\n    stringedValue === 'StringContaining'\n    || stringedValue === 'StringNotContaining'\n  ) {\n    return (\n      stringedValue\n      + SPACE\n      + printer(val.sample, config, indentation, depth, refs)\n    )\n  }\n\n  if (typeof val.toAsymmetricMatcher !== 'function') {\n    throw new TypeError(\n      `Asymmetric matcher ${val.constructor.name} does not implement toAsymmetricMatcher()`,\n    )\n  }\n\n  return val.toAsymmetricMatcher()\n}\n\nconst test: NewPlugin['test'] = (val: any) =>\n  val && val.$$typeof === asymmetricMatcher\n\nconst plugin: NewPlugin = { serialize, test }\n\nexport default plugin\n","sourceCodeStart":66,"sourceCodeEnd":98,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/pretty-format/src/plugins/AsymmetricMatcher.ts#L66-L98","documentation":"The AsymmetricMatcher pretty-format plugin serializes objects carrying the asymmetric matcher $$typeof symbol. After handling built-in matchers (StringMatching, StringContaining and their negations), if the matcher object has no toAsymmetricMatcher() method the plugin cannot render it and throws. This protects against custom matcher objects that declare the asymmetric typeof but skip the serialization contract.","triggerScenarios":"Defining a custom asymmetric matcher (object with $$typeof equal to the asymmetricMatcher symbol) without implementing toAsymmetricMatcher(); passing such a matcher to expect/pretty-format output.","commonSituations":"Extending expect with a custom matcher class that sets $$typeof but forgets the serialize method; using a matcher from a library that does not implement the full asymmetric matcher interface; version mismatch in the asymmetric matcher symbol.","solutions":[],"exampleFix":"// before\nclass FooMatcher { $$typeof = asymmetricMatcher; sample = 'x' }\n// after\nclass FooMatcher { $$typeof = asymmetricMatcher; sample = 'x'; toAsymmetricMatcher() { return `Foo<${this.sample}>` } }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isSerializableMatcher(v: any): boolean {\n  return v && v.$$typeof === Symbol.for('jest.asymmetricMatcher') && typeof v.toAsymmetricMatcher === 'function'\n}","tryCatchPattern":null,"preventionTips":["Implement toAsymmetricMatcher() on every custom matcher class","Extend a built-in matcher base that already serializes","Unit-test custom matchers through pretty-format to catch missing serialization"],"tags":["pretty-format","asymmetric-matcher","expect","plugin"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}