chroma-core/chroma · error · ChromaValueError
Expected operand value to be a string, number, or boolean fo
Error message
Expected operand value to be a string, number, or boolean for ${operator}, but got ${typeof operand} What it means
$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.
Source
Thrown at clients/new-js/packages/chromadb/src/utils.ts:598
["$gt", "$gte", "$lt", "$lte"].includes(operator) &&
typeof operand !== "number"
) {
throw new ChromaValueError(
`Expected operand value to be a number for ${operator}, but got ${typeof operand}`,
);
}
if (["$in", "$nin"].includes(operator) && !Array.isArray(operand)) {
throw new ChromaValueError(
`Expected operand value to be an array for ${operator}, but got ${operand}`,
);
}
if (
["$contains", "$not_contains"].includes(operator) &&
!["string", "number", "boolean"].includes(typeof operand)
) {
throw new ChromaValueError(
`Expected operand value to be a string, number, or boolean for ${operator}, but got ${typeof operand}`,
);
}
if (
![
"$gt",
"$gte",
"$lt",
"$lte",
"$ne",
"$eq",
"$in",
"$nin",
"$contains",
"$not_contains",
].includes(operator)
) {View on GitHub (pinned to aecdd12c8a)
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.
Example fix
// before
where: { title: { $contains: ['ai', 'ml'] } }
// after
where: { $or: [{ title: { $contains: 'ai' } }, { title: { $contains: 'ml' } }] } Defensive patterns
Strategy: validation
Validate before calling
const isScalar = (v) => ['string', 'number', 'boolean'].includes(typeof v);
const containsAny = (field, terms) => terms.length === 1
? { [field]: { $contains: terms[0] } }
: { $or: terms.map(t => ({ [field]: { $contains: t } })) };
await collection.query({ queryTexts, where: containsAny('title', ['ai', 'ml']) }); Type guard
const isContainsOperand = (v: unknown): v is string | number | boolean => ['string', 'number', 'boolean'].includes(typeof v);
Try / catch
try {
await collection.query({ queryTexts, where });
} catch (e) {
if ((e as Error).message.includes('boolean for $contains')) {
// expand the list into $or clauses of scalar $contains and retry
} else {
throw e;
}
} Prevention
- Pass exactly one scalar per $contains clause.
- Combine multi-keyword filters with $or.
- Filter out null/undefined search terms before building the clause.
When it happens
Trigger: where: { title: { $contains: ['ai', 'ml'] } } — array operand. { $contains: null }. Passing a regex object as the needle.
Common situations: Trying to express multi-keyword search with one $contains; optional search terms defaulting to null; assuming regex support.
Related errors
- Expected where to be a non-empty object
- Expected 'where' to have exactly one operator, but got ${Obj
- Expected 'where' value to be a string, number, boolean, or a
- Expected 'where' value for $and or $or to be a list of 'wher
- Expected operator expression to have one operator, but got $
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/096a15f20a2635ec.
Report an issue: GitHub.