{"record":{"id":"72d33222fb4e0180","repo":"chroma-core/chroma","slug":"expected-operand-value-to-be-a-string-number-boo","errorCode":null,"errorMessage":"Expected operand value to be a string, number, boolean, or a list of those types","messagePattern":"Expected operand value to be a string, number, boolean, or a list of those types","errorType":"validation","errorClass":"ChromaValueError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/utils.ts","lineNumber":626,"sourceCode":"          \"$lte\",\n          \"$ne\",\n          \"$eq\",\n          \"$in\",\n          \"$nin\",\n          \"$contains\",\n          \"$not_contains\",\n        ].includes(operator)\n      ) {\n        throw new ChromaValueError(\n          `Expected operator to be one of $gt, $gte, $lt, $lte, $ne, $eq, $in, $nin, $contains, $not_contains, but got ${operator}`,\n        );\n      }\n\n      if (\n        ![\"string\", \"number\", \"boolean\"].includes(typeof operand) &&\n        !Array.isArray(operand)\n      ) {\n        throw new ChromaValueError(\n          \"Expected operand value to be a string, number, boolean, or a list of those types\",\n        );\n      }\n\n      if (\n        Array.isArray(operand) &&\n        (operand.length === 0 ||\n          !operand.every((item) => typeof item === typeof operand[0]))\n      ) {\n        throw new ChromaValueError(\n          \"Expected 'where' operand value to be a non-empty list and all values to be of the same type\",\n        );\n      }\n    }\n  });\n};\n\n/**","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/utils.ts#L608-L644","documentation":"As the final gate on operator operands, validateWhere requires a scalar (string/number/boolean) or an array; objects, null, undefined, and functions throw ChromaValueError. Notably this rejects { $eq: null } and { $ne: null } — Chroma where filters cannot compare against null. Nested objects as operands are also invalid.","triggerScenarios":"where: { finished_at: { $eq: null } } — attempting to match missing metadata. { field: { $ne: undefined } }. { $gt: { value: 10 } } (wrapped object).","commonSituations":"Optional fields modeled as null in metadata and filtered with $eq: null; building operands from nested config objects; undefined leaking through from JS option objects.","solutions":["Chroma cannot filter on null/missing metadata — restructure so absence is a stored value, e.g. a boolean flag or the string 'none'.","Unwrap nested objects to the scalar before use.","Filter out undefined operands when building the where clause."],"exampleFix":"// before\nwhere: { finished_at: { $eq: null } }\n\n// after (store a boolean flag at ingestion)\nwhere: { is_finished: false }","handlingStrategy":"type-guard","validationCode":"const isOperand = (v) =>\n  ['string', 'number', 'boolean'].includes(typeof v) || Array.isArray(v);\nconst operandsOk = Object.values(where).every(v =>\n  typeof v !== 'object' || v === null ? isOperand(v) : Object.values(v).every(isOperand)\n);\nif (!operandsOk) throw new Error('Where operands must be scalars or arrays, not null/objects');","typeGuard":"const isScalarOrList = (v: unknown): v is string | number | boolean | unknown[] =>\n  ['string', 'number', 'boolean'].includes(typeof v) || Array.isArray(v);","tryCatchPattern":"try {\n  await collection.query({ queryTexts, where });\n} catch (e) {\n  if ((e as Error).message.includes('string, number, boolean, or a list')) {\n    // replace null operands with a stored sentinel value and retry\n  } else {\n    throw e;\n  }\n}","preventionTips":["Never filter with $eq: null / $ne: null — Chroma does not support null comparisons.","Model optional fields as stored sentinels (false, 'none') at ingestion time.","Keep operands flat scalars or scalar lists."],"tags":["where-filter","validation","null-handling"],"backgroundTag":"invalid-where-clause","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}