{"record":{"id":"971ba9e92d950478","repo":"vitest-dev/vitest","slug":"you-must-provide-an-object-to-this-tostring","errorCode":null,"errorMessage":"You must provide an object to ${this.toString()}, not '${typeof this.sample}'.","messagePattern":"You must provide an object to (.+?), not '(.+?)'\\.","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/expect/src/jest-asymmetric-matchers.ts","lineNumber":154,"sourceCode":"    if (Object.hasOwn(obj, property)) {\n      return true\n    }\n\n    return this.hasProperty(this.getPrototype(obj), property)\n  }\n\n  getProperties(obj: object): (string | symbol)[] {\n    return [\n      ...Object.keys(obj),\n      ...Object.getOwnPropertySymbols(obj).filter(\n        s => Object.getOwnPropertyDescriptor(obj, s)?.enumerable,\n      ),\n    ]\n  }\n\n  asymmetricMatch(other: any, customTesters?: Array<Tester>): boolean {\n    if (typeof this.sample !== 'object') {\n      throw new TypeError(\n        `You must provide an object to ${this.toString()}, not '${typeof this\n          .sample}'.`,\n      )\n    }\n\n    let result = true\n\n    const properties = this.getProperties(this.sample)\n    for (const property of properties) {\n      if (\n        !this.hasProperty(other, property)\n      ) {\n        result = false\n        break\n      }\n      const value = this.sample[property]\n      const otherValue = other[property]\n      if (!equals(","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/vitest-dev/vitest/blob/1fa9837ec26533512fdcad8baebf249771bd340a/packages/expect/src/jest-asymmetric-matchers.ts#L136-L172","documentation":"ObjectContaining's asymmetricMatch throws a TypeError if this.sample is not an object. This is a match-time guard (inside asymmetricMatch), so the error fires when the matcher is actually evaluated against a value, not when expect.objectContaining is constructed.","triggerScenarios":"expect.objectContaining(sample) built with a non-object sample (string/number/null), then used in an assertion like toEqual(expect.objectContaining(...)).","commonSituations":"Passing a primitive to objectContaining; a default parameter that resolved to undefined; constructing the matcher from untyped config data.","solutions":["Pass an object literal describing the required subset: expect.objectContaining({ id: 1 }).","If you only need a single primitive property, wrap it: expect.objectContaining({ status: 'active' }).","Validate the shape before constructing the matcher in dynamic scenarios."],"exampleFix":"// before\nexpect(res).toEqual(expect.objectContaining('id'))\n// after\nexpect(res).toEqual(expect.objectContaining({ id: 1, active: true }))","handlingStrategy":"type-guard","validationCode":"function asObjectContaining(sample) {\n  if (sample === null || typeof sample !== 'object') {\n    throw new TypeError('expect.objectContaining needs a plain object')\n  }\n  return expect.objectContaining(sample)\n}","typeGuard":"function isPlainObject(v): v is Record<string, unknown> {\n  return v !== null && typeof v === 'object' && !Array.isArray(v)\n}","tryCatchPattern":null,"preventionTips":["Always pass an object literal to expect.objectContaining.","When constructing dynamically, validate it is a non-null object first.","Remember the check fires at match time, not construction."],"tags":["expect","asymmetric-matcher","type-error"],"backgroundTag":null,"analyzedSha":"1fa9837ec26533512fdcad8baebf249771bd340a","analyzedAt":"2026-08-11T16:11:39.638Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}