chroma-core/chroma · error · TypeError
$and must be a non-empty array
Error message
$and must be a non-empty array
What it means
Thrown by parseWhereDict (where.ts:165) when the value of $and is not a non-empty array. The $and combinator must receive an array containing at least one clause; an empty array, a single clause object, a string, or null all throw this TypeError. Note $or has the identical rule in its own branch.
Source
Thrown at clients/new-js/packages/chromadb/src/execution/expression/where.ts:165
["$in", (key, value) => new ComparisonWhere(key, "$in", value)],
["$nin", (key, value) => new ComparisonWhere(key, "$nin", value)],
["$contains", (key, value) => new ComparisonWhere(key, "$contains", value)],
[
"$not_contains",
(key, value) => new ComparisonWhere(key, "$not_contains", value),
],
["$regex", (key, value) => new ComparisonWhere(key, "$regex", value)],
["$not_regex", (key, value) => new ComparisonWhere(key, "$not_regex", value)],
]);
const parseWhereDict = (data: Record<string, unknown>): WhereExpression => {
if ("$and" in data) {
if (Object.keys(data).length !== 1) {
throw new Error("$and cannot be combined with other keys");
}
const rawConditions = data["$and"];
if (!Array.isArray(rawConditions) || rawConditions.length === 0) {
throw new TypeError("$and must be a non-empty array");
}
const conditions = rawConditions.map((item, index) => {
const expr = WhereExpression.from(item as WhereInput);
if (!expr) {
throw new TypeError(`Invalid where clause at index ${index}`);
}
return expr;
});
if (conditions.length === 1) {
return conditions[0];
}
return conditions
.slice(1)
.reduce(
(acc, condition) => AndWhere.combine(acc, condition),
conditions[0],
);
}View on GitHub (pinned to aecdd12c8a)
Solutions
- Use a non-empty array: { $and: [condA, condB] }
- For a single condition, drop $and entirely: just { field: { $eq: value } }
- Guard dynamic lists: clauses.length ? { $and: clauses } : clauses[0] ?? undefined
Example fix
// before
const where = { $and: conditions.filter(enabled) }; // may be []
// after
const clauses = conditions.filter(enabled);
const where = clauses.length > 1 ? { $and: clauses } : clauses[0]; Defensive patterns
Strategy: validation
Validate before calling
const clauses = rawClauses.filter(c => c != null);
if (clauses.length === 0) throw new Error('no where clauses to combine');
const where = clauses.length > 1 ? { $and: clauses } : clauses[0]; Type guard
const isNonEmptyClauseArray = (v: unknown): v is object[] => Array.isArray(v) && v.length > 0;
Try / catch
try {
const results = await collection.query({ where });
} catch (e) {
if (e instanceof TypeError && e.message.includes('non-empty array')) {
return collection.query({}); // drop the empty filter
}
throw e;
} Prevention
- $and takes an array of clauses — always array the value, even for one clause (or drop $and)
- Check clauses.length before building the filter
- The same rule applies to $or
When it happens
Trigger: Passing { $and: [] } — e.g. the filter list was empty at runtime after all conditions were filtered out; { $and: { a: 1 } } — wrapping a single clause in $and without arraying it; { $and: null } or { $and: 'x' } from malformed config.
Common situations: Dynamically built filter lists where zero conditions matched (empty feature list, all optional filters unset); refactoring a single-condition filter into $and form without converting the value to an array; JSON configs where $and was hand-written as an object.
Related errors
- $and cannot be combined with other keys
- Invalid where clause at index ${index}
- $or cannot be combined with other keys
- Rrf requires at least one rank expression
- Where input must be a WhereExpression or plain object
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/c8f96d976c6f0a30.
Report an issue: GitHub.