{"record":{"id":"fb7acd81127ff196","repo":"awslabs/llrt","slug":"expected-is-not-a-string","errorCode":null,"errorMessage":"Expected is not a string","messagePattern":"Expected is not a string","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"llrt_core/src/modules/js/@llrt/expect/jest-asymmetric-matchers.ts","lineNumber":83,"sourceCode":"\n  abstract asymmetricMatch(other: unknown): boolean;\n  abstract toString(): string;\n  getExpectedType?(): string;\n  toAsymmetricMatcher?(): string;\n\n  // implement custom chai/loupe inspect for better AssertionError.message formatting\n  // https://github.com/chaijs/loupe/blob/9b8a6deabcd50adc056a64fb705896194710c5c6/src/index.ts#L29\n  [Symbol.for(\"chai/inspect\")](options: { depth: number; truncate: number }) {\n    // minimal pretty-format with simple manual truncation\n    const result = stringify(this, options.depth, { min: true });\n    if (result.length <= options.truncate) return result;\n    return `${this.toString()}{…}`;\n  }\n}\n\nexport class StringContaining extends AsymmetricMatcher<string> {\n  constructor(sample: string, inverse = false) {\n    if (!isA(\"String\", sample)) throw new Error(\"Expected is not a string\");\n\n    super(sample, inverse);\n  }\n\n  asymmetricMatch(other: string) {\n    const result = isA(\"String\", other) && other.includes(this.sample);\n\n    return this.inverse ? !result : result;\n  }\n\n  toString() {\n    return `String${this.inverse ? \"Not\" : \"\"}Containing`;\n  }\n\n  getExpectedType() {\n    return \"string\";\n  }\n}","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/awslabs/llrt/blob/742fc00b82cbeaab1c1b76f0d706c302a5cbc306/llrt_core/src/modules/js/@llrt/expect/jest-asymmetric-matchers.ts#L65-L101","documentation":"StringContaining is an asymmetric matcher that checks whether another string includes the given sample substring. The constructor validates that the sample is actually a string using isA(\"String\", sample) and throws this plain Error if not, so malformed matchers fail fast instead of silently never matching. It mirrors Jest's own validation for expect.stringContaining.","triggerScenarios":"Calling expect.stringContaining(x) (or expect.not.stringContaining(x)) where x is not a string — e.g. a number, null, undefined, or an object.","commonSituations":"Passing a number that looks like text (stringContaining(123)), passing a variable that is undefined due to a typo or failed lookup, or copying matchers between expect().toContain and expect().toStrictEqual where argument types differ.","solutions":["Convert the sample to a string before passing it, e.g. expect.stringContaining(String(value)).","Verify the variable actually holds a string; fix the source of the non-string value (often an API response field or undefined variable).","Use expect.any(String) instead if you only care that the value is a string.","Use expect.arrayContaining/objectContaining if you meant to match a non-string structure."],"exampleFix":"// before\nexpect(log).toEqual(expect.stringContaining(404));\n// after\nexpect(log).toEqual(expect.stringContaining(String(404)));","handlingStrategy":"type-guard","validationCode":"if (typeof sample !== 'string') throw new TypeError('stringContaining sample must be a string');","typeGuard":"const isStr = (v: unknown): v is string => typeof v === 'string';","tryCatchPattern":"try { expect(x).toEqual(expect.stringContaining(s)); } catch (e) { if (!(e instanceof Error) || !/Expected is not a string/.test(e.message)) throw e; /* handle bad sample */ }","preventionTips":["Always pass string literals or values narrowed to string","Enable TypeScript strict mode so non-strings are flagged at compile time","Prefer expect.any(String) when validating type only","Check for undefined variables that commonly carry the substring"],"tags":["testing","validation","asymmetric-matcher","typescript"],"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"}