{"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/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/expect/src/jest-asymmetric-matchers.ts#L136-L172","documentation":"Thrown as a TypeError inside ObjectContaining.asymmetricMatch when this.sample is not an object. ObjectContaining checks that the received value has (and equals) a set of expected properties, so the expected sample must be a property bag.","triggerScenarios":"Constructing expect.objectContaining(value) where value is a primitive (string, number, null, undefined) — the constructor accepts it but matching throws because typeof this.sample !== 'object'.","commonSituations":"Passing a single key name instead of an object; passing null/undefined; a variable that was expected to be an object but is actually a primitive after a refactor.","solutions":["Pass an object literal of expected properties: expect.objectContaining({ id: 1 }).","If you only need key presence, wrap the key: expect.objectContaining({ key: expect.anything() }).","Validate the variable is an object before using it as the sample."],"exampleFix":"// before\nexpect(res).toEqual(expect.objectContaining('id'))\n// after\nexpect(res).toEqual(expect.objectContaining({ id: expect.any(Number) }))","handlingStrategy":"type-guard","validationCode":"function asRecord(v: unknown): Record<string, unknown> {\n  if (typeof v !== 'object' || v === null || Array.isArray(v)) {\n    throw new TypeError(`objectContaining needs an object, got ${typeof v}`)\n  }\n  return v as Record<string, unknown>\n}\nexpect(res).toEqual(expect.objectContaining(asRecord(shape)))","typeGuard":"function isPlainObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}","tryCatchPattern":null,"preventionTips":["Always pass object literals ({...}) to objectContaining.","Reject null/arrays at the type level when building dynamic expected shapes.","Wrap single key checks as { key: expect.anything() }."],"tags":["expect","asymmetric-matcher","assertion","typescript"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}