chroma-core/chroma · error · Error
Operator dictionary for field "${field}" must contain exactl
Error message
Operator dictionary for field "${field}" must contain exactly one operator What it means
When a field's value in a where dict is a plain object, the parser treats it as an operator dictionary that must contain exactly one operator key. Two operators on the same field in one dict — typically a range like { price: { $gte: 10, $lte: 100 } } — are rejected, as is an empty operator object { field: {} }. Split the operators into separate clauses joined by $and.
Source
Thrown at clients/new-js/packages/chromadb/src/execution/expression/where.ts:223
.reduce(
(acc, condition) => OrWhere.combine(acc, condition),
conditions[0],
);
}
const entries = Object.entries(data);
if (entries.length !== 1) {
throw new Error("Where dictionary must contain exactly one field");
}
const [field, value] = entries[0];
if (!isPlainObject(value)) {
return new ComparisonWhere(field, "$eq", value);
}
const operatorEntries = Object.entries(value);
if (operatorEntries.length !== 1) {
throw new Error(
`Operator dictionary for field "${field}" must contain exactly one operator`,
);
}
const [operator, operand] = operatorEntries[0];
const factory = comparisonOperatorMap.get(operator);
if (!factory) {
throw new Error(`Unsupported where operator: ${operator}`);
}
return factory(field, operand);
};
export const createComparisonWhere = (
key: string,
operator: string,
value: unknown,
): WhereExpression => new ComparisonWhere(key, operator, value);View on GitHub (pinned to aecdd12c8a)
Solutions
- Split the range: { $and: [{ price: { $gte: 10 } }, { price: { $lte: 100 } }] }.
- Or use the builder: WhereExpression.from({ price: { $gte: 10 } }).and({ price: { $lte: 100 } }).
- If the two operators were meant as alternatives, join them with $or instead.
- Guard against empty operator dicts when generating filters dynamically.
Example fix
// before
where: { price: { $gte: 10, $lte: 100 } }
// after
where: { $and: [{ price: { $gte: 10 } }, { price: { $lte: 100 } }] } Defensive patterns
Strategy: validation
Validate before calling
function rangeFilter(field: string, min: number, max: number) {
return { $and: [{ [field]: { $gte: min } }, { [field]: { $lte: max } }] };
} Type guard
function isSingleOperatorDict(value: unknown): boolean {
if (typeof value !== 'object' || value === null || Array.isArray(value)) return true;
return Object.keys(value).length === 1;
} Try / catch
try {
await collection.query({ where });
} catch (e) {
if (e instanceof Error && e.message.includes('must contain exactly one operator')) {
// split the field's operator dict into $and-joined single-operator clauses
} else {
throw e;
}
} Prevention
- Use one operator per field dict; join ranges with $and.
- Write range/equality/set filter helpers once instead of hand-building multi-operator dicts.
- Add table-driven unit tests for your filter builder covering range, set, and substring cases.
When it happens
Trigger: Range filters: where: { price: { $gte: 10, $lte: 100 } }; time windows: { ts: { $gt: start, $lt: end } }; two equality-ish operators in one dict: { status: { $eq: 'a', $ne: 'b' } }; { field: {} } built when an operator/value lookup came back empty.
Common situations: Porting MongoDB range queries that allow multiple operators per field; date/time-window filters; price slider UIs; filter builders that merge operator dicts with spread.
Related errors
- $or must be a non-empty array
- Where dictionary must contain exactly one field
- Unsupported where operator: ${operator}
- K.DOCUMENT.contains requires a string value
- K.DOCUMENT.notContains requires a string value
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/65206e4c3143193f.
Report an issue: GitHub.