{"record":{"id":"096a15f20a2635ec","repo":"chroma-core/chroma","slug":"expected-operand-value-to-be-a-string-number-or","errorCode":null,"errorMessage":"Expected operand value to be a string, number, or boolean for ${operator}, but got ${typeof operand}","messagePattern":"Expected operand value to be a string, number, or boolean for (.+?), but got (.+?)","errorType":"validation","errorClass":"ChromaValueError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/utils.ts","lineNumber":598,"sourceCode":"        [\"$gt\", \"$gte\", \"$lt\", \"$lte\"].includes(operator) &&\n        typeof operand !== \"number\"\n      ) {\n        throw new ChromaValueError(\n          `Expected operand value to be a number for ${operator}, but got ${typeof operand}`,\n        );\n      }\n\n      if ([\"$in\", \"$nin\"].includes(operator) && !Array.isArray(operand)) {\n        throw new ChromaValueError(\n          `Expected operand value to be an array for ${operator}, but got ${operand}`,\n        );\n      }\n\n      if (\n        [\"$contains\", \"$not_contains\"].includes(operator) &&\n        ![\"string\", \"number\", \"boolean\"].includes(typeof operand)\n      ) {\n        throw new ChromaValueError(\n          `Expected operand value to be a string, number, or boolean for ${operator}, but got ${typeof operand}`,\n        );\n      }\n\n      if (\n        ![\n          \"$gt\",\n          \"$gte\",\n          \"$lt\",\n          \"$lte\",\n          \"$ne\",\n          \"$eq\",\n          \"$in\",\n          \"$nin\",\n          \"$contains\",\n          \"$not_contains\",\n        ].includes(operator)\n      ) {","sourceCodeStart":580,"sourceCodeEnd":616,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/utils.ts#L580-L616","documentation":"$contains and $not_contains accept only scalar string, number, or boolean operands; validateWhere throws for arrays, objects, null, or undefined. These operators do substring matching against a single value — a list of needles is not supported and must be expanded into multiple clauses.","triggerScenarios":"where: { title: { $contains: ['ai', 'ml'] } } — array operand. { $contains: null }. Passing a regex object as the needle.","commonSituations":"Trying to express multi-keyword search with one $contains; optional search terms defaulting to null; assuming regex support.","solutions":["Use one scalar per clause and combine: { $or: [{ title: { $contains: 'ai' } }, { title: { $contains: 'ml' } }] }.","Skip the clause when the term is null/undefined.","For document text filtering use whereDocument's $contains instead of a metadata clause."],"exampleFix":"// before\nwhere: { title: { $contains: ['ai', 'ml'] } }\n\n// after\nwhere: { $or: [{ title: { $contains: 'ai' } }, { title: { $contains: 'ml' } }] }","handlingStrategy":"validation","validationCode":"const isScalar = (v) => ['string', 'number', 'boolean'].includes(typeof v);\nconst containsAny = (field, terms) => terms.length === 1\n  ? { [field]: { $contains: terms[0] } }\n  : { $or: terms.map(t => ({ [field]: { $contains: t } })) };\nawait collection.query({ queryTexts, where: containsAny('title', ['ai', 'ml']) });","typeGuard":"const isContainsOperand = (v: unknown): v is string | number | boolean =>\n  ['string', 'number', 'boolean'].includes(typeof v);","tryCatchPattern":"try {\n  await collection.query({ queryTexts, where });\n} catch (e) {\n  if ((e as Error).message.includes('boolean for $contains')) {\n    // expand the list into $or clauses of scalar $contains and retry\n  } else {\n    throw e;\n  }\n}","preventionTips":["Pass exactly one scalar per $contains clause.","Combine multi-keyword filters with $or.","Filter out null/undefined search terms before building the clause."],"tags":["where-filter","validation","contains"],"backgroundTag":"invalid-where-clause","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}