chroma-core/chroma · error · TypeError
Where input must be a WhereExpression or plain object
Error message
Where input must be a WhereExpression or plain object
What it means
Thrown by WhereExpression.from (where.ts:35) when a where filter is neither a WhereExpression instance, null/undefined, nor a plain object (Object.prototype or null prototype, not an array). The dict form is then parsed by parseWhereDict. This is a strict structural gate: arrays of clauses, primitives, Maps, and class instances are all rejected client-side before any request.
Source
Thrown at clients/new-js/packages/chromadb/src/execution/expression/where.ts:35
public or(other: WhereInput): WhereExpression {
const target = WhereExpression.from(other);
if (!target) {
return this as unknown as WhereExpression;
}
return OrWhere.combine(this as unknown as WhereExpression, target);
}
}
export abstract class WhereExpression extends WhereExpressionBase {
public static from(input: WhereInput): WhereExpression | undefined {
if (input instanceof WhereExpression) {
return input;
}
if (input === null || input === undefined) {
return undefined;
}
if (!isPlainObject(input)) {
throw new TypeError(
"Where input must be a WhereExpression or plain object",
);
}
return parseWhereDict(input);
}
}
class AndWhere extends WhereExpression {
constructor(private readonly conditions: WhereExpression[]) {
super();
}
public toJSON(): WhereJSON {
return { $and: this.conditions.map((condition) => condition.toJSON()) };
}
public get operands(): WhereExpression[] {
return this.conditions.slice();View on GitHub (pinned to aecdd12c8a)
Solutions
- Pass a single plain-object dict: where({ genre: { $eq: 'sci-fi' } })
- Combine multiple clauses with $and/$or keys or build with WhereExpression .and()/.or()
- For class-instance sources, serialize first (JSON.parse(JSON.stringify(obj))) or construct the dict explicitly
Example fix
// before
const results = await collection.query({ where: [condA, condB] }); // array throws
// after
const results = await collection.query({
where: { $and: [condA, condB] },
}); Defensive patterns
Strategy: type-guard
Validate before calling
const isPlainObjectLike = (v: unknown): v is Record<string, unknown> => {
if (typeof v !== 'object' || v === null || Array.isArray(v)) return false;
const p = Object.getPrototypeOf(v);
return p === Object.prototype || p === null;
};
if (!isPlainObjectLike(where)) throw new Error('where must be a dict'); Type guard
const isWhereDict = (v: unknown): v is Record<string, unknown> => isPlainObjectLike(v); // WhereExpression instances also accepted by WhereExpression.from
Try / catch
try {
const results = await collection.query({ where });
} catch (e) {
if (e instanceof TypeError && e.message.includes('Where input')) {
throw new Error(`Invalid where filter shape: ${JSON.stringify(where)}`);
}
throw e;
} Prevention
- Pass one dict; nest multiple conditions under $and/$or instead of an array
- JSON.parse'd filters are safe; class instances and Maps are not — serialize or rebuild them
- Avoid double-wrapping like { where: { where: {...} } }
When it happens
Trigger: Passing where: [{ genre: {$eq: 'a'} }, { year: {$gt: 2020} }] — an array of clauses instead of one dict (nest them under $and instead); where: 'genre' or where: 42 — a primitive; where: someClassInstance — an object whose prototype is not Object.prototype; calling expr.and(mapObject) with a Map.
Common situations: Translating Mongo-style filters where an array of conditions is idiomatic; filters built by class hierarchies or from libraries that return wrapped objects; JSON filters are safe (JSON.parse yields plain objects) but Object.create(customProto) is not; wrapping the filter in an extra layer like { where: {...} } by mistake.
Related errors
- Knn key must be a string or Key instance
- Select keys must be strings or Key instances
- Knn limit must be a positive integer
- Rrf k must be a positive integer
- Unsupported select input
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/83585dc628611c2d.
Report an issue: GitHub.