{"record":{"id":"4064c34ed7069683","repo":"awslabs/llrt","slug":"you-must-provide-an-object-to-this-tostring-not-typeof-this","errorCode":null,"errorMessage":"You must provide an object to ${this.toString()}, not '${typeof this.sample}'.","messagePattern":"You must provide an object to (.+?), not '(.+?)'\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"llrt_core/src/modules/js/@llrt/expect/jest-asymmetric-matchers.ts","lineNumber":142,"sourceCode":"  getPrototype(obj: object) {\n    if (Object.getPrototypeOf) return Object.getPrototypeOf(obj);\n\n    if (obj.constructor.prototype === obj) return null;\n\n    return obj.constructor.prototype;\n  }\n\n  hasProperty(obj: object | null, property: string): boolean {\n    if (!obj) return false;\n\n    if (Object.prototype.hasOwnProperty.call(obj, property)) return true;\n\n    return this.hasProperty(this.getPrototype(obj), property);\n  }\n\n  asymmetricMatch(other: any) {\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 matcherContext = this.getMatcherContext()\n    for (const property in this.sample) {\n      if (\n        !this.hasProperty(other, property) ||\n        !equals(this.sample[property], other[property], [])\n      ) {\n        result = false;\n        break;\n      }\n    }\n","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/awslabs/llrt/blob/742fc00b82cbeaab1c1b76f0d706c302a5cbc306/llrt_core/src/modules/js/@llrt/expect/jest-asymmetric-matchers.ts#L124-L160","documentation":"ObjectContaining.asymmetricMatch validates its own sample each time it matches. If the sample given to expect.objectContaining(...) was not an object (e.g. a string, number, or undefined), it throws this TypeError during matching rather than producing a wrong result. The message interpolates the matcher name and the actual typeof of the bad sample.","triggerScenarios":"expect.objectContaining(42), expect.objectContaining('foo'), or expect.objectContaining(undefined) — the throw happens when the matcher is actually applied to a value, not at construction.","commonSituations":"Passing a JSON-decoded value that turned out to be a scalar, passing an array where an object was intended, or calling objectContaining() with no arguments (sample undefined) after a refactor.","solutions":["Pass a plain object of expected properties: expect.objectContaining({ id: 1 }).","Check that the variable holding the sample is not undefined/null at match time.","Use expect.anything() or expect.any(Type) for non-object matching needs.","Wrap nested matchers correctly — nested samples must themselves be objects."],"exampleFix":"// before\nexpect(user).toEqual(expect.objectContaining('name'));\n// after\nexpect(user).toEqual(expect.objectContaining({ name: expect.any(String) }));","handlingStrategy":"type-guard","validationCode":"if (sample === null || typeof sample !== 'object' || Array.isArray(sample)) throw new TypeError('objectContaining sample must be a plain object');","typeGuard":"const isObj = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);","tryCatchPattern":"try { expect(v).toEqual(expect.objectContaining(spec)); } catch (e) { /* log and fall back to a plain toEqual assertion */ }","preventionTips":["Never call objectContaining() with zero arguments","Ensure the spec object is not undefined due to failed imports","Use objectContaining only for keyed data; arrays belong to arrayContaining","Type the spec as Record<string, unknown> in tests"],"tags":["testing","type-mismatch","asymmetric-matcher"],"backgroundTag":"invalid-argument-value","analyzedSha":"742fc00b82cbeaab1c1b76f0d706c302a5cbc306","analyzedAt":"2026-09-12T11:14:07.838Z","contentChangedAt":"2026-09-12T11:14:07.838Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}