chroma-core/chroma · error · ChromaValueError
Expected operator expression to have one operator, but got $
Error message
Expected operator expression to have one operator, but got ${value} What it means
When a field's value is an object, it is treated as an operator expression and must contain exactly one operator key. Combining two operators on one field — the classic range query { $gt: 1, $lt: 5 } — throws ChromaValueError because the expression has two keys. Range conditions must be split into separate clauses joined with $and.
Source
Thrown at clients/new-js/packages/chromadb/src/utils.ts:572
throw new ChromaValueError(
`Expected 'where' value to be a string, number, boolean, or an operator expression, but got ${value}`,
);
}
if (key === "$and" || key === "$or") {
if (Object.keys(value).length <= 1) {
throw new ChromaValueError(
`Expected 'where' value for $and or $or to be a list of 'where' expressions, but got ${value}`,
);
}
value.forEach((w: Where) => validateWhere(w));
return;
}
if (typeof value === "object") {
if (Object.keys(value).length != 1) {
throw new ChromaValueError(
`Expected operator expression to have one operator, but got ${value}`,
);
}
const [operator, operand] = Object.entries(value)[0];
if (
["$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}`,View on GitHub (pinned to aecdd12c8a)
Solutions
- Split multi-operator fields: { $and: [{ year: { $gt: 2000 } }, { year: { $lt: 2010 } }] }.
- Keep exactly one operator per brace block for a field.
- For plain equality use the shorthand { field: value } instead of an operator object.
Example fix
// before
where: { year: { $gt: 2000, $lt: 2010 } }
// after
where: { $and: [{ year: { $gt: 2000 } }, { year: { $lt: 2010 } }] } Defensive patterns
Strategy: validation
Validate before calling
const range = (field, min, max) => ({
$and: [{ [field]: { $gt: min } }, { [field]: { $lt: max } }],
});
await collection.query({ queryTexts, where: range('year', 2000, 2010) }); Type guard
const isSingleOperatorExpr = (v: object) => Object.keys(v).length === 1 && Object.keys(v)[0].startsWith('$'); Try / catch
try {
await collection.query({ queryTexts, where });
} catch (e) {
if ((e as Error).message.includes('one operator')) {
// split the multi-operator expression into $and clauses and retry
} else {
throw e;
}
} Prevention
- One operator per field expression — split ranges into $and clauses.
- Provide a range() helper so callers never hand-write multi-operator objects.
- For equality prefer the { field: value } shorthand.
When it happens
Trigger: where: { year: { $gt: 2000, $lt: 2010 } }. Two operators in one brace block, e.g. { $contains: 'a', $eq: 'b' }. An empty operator object { field: {} } (0 keys).
Common situations: Porting range/date filters from Mongo or SQL BETWEEN syntax; assuming operator objects compose implicitly with AND inside one field expression.
Related errors
- Operator dictionary for field "${field}" must contain exactl
- 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
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/54243934f6325b21.
Report an issue: GitHub.