{"record":{"id":"83585dc628611c2d","repo":"chroma-core/chroma","slug":"where-input-must-be-a-whereexpression-or-plain-obj","errorCode":null,"errorMessage":"Where input must be a WhereExpression or plain object","messagePattern":"Where input must be a WhereExpression or plain object","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/execution/expression/where.ts","lineNumber":35,"sourceCode":"  public or(other: WhereInput): WhereExpression {\n    const target = WhereExpression.from(other);\n    if (!target) {\n      return this as unknown as WhereExpression;\n    }\n    return OrWhere.combine(this as unknown as WhereExpression, target);\n  }\n}\n\nexport abstract class WhereExpression extends WhereExpressionBase {\n  public static from(input: WhereInput): WhereExpression | undefined {\n    if (input instanceof WhereExpression) {\n      return input;\n    }\n    if (input === null || input === undefined) {\n      return undefined;\n    }\n    if (!isPlainObject(input)) {\n      throw new TypeError(\n        \"Where input must be a WhereExpression or plain object\",\n      );\n    }\n    return parseWhereDict(input);\n  }\n}\n\nclass AndWhere extends WhereExpression {\n  constructor(private readonly conditions: WhereExpression[]) {\n    super();\n  }\n\n  public toJSON(): WhereJSON {\n    return { $and: this.conditions.map((condition) => condition.toJSON()) };\n  }\n\n  public get operands(): WhereExpression[] {\n    return this.conditions.slice();","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/execution/expression/where.ts#L17-L53","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst results = await collection.query({ where: [condA, condB] }); // array throws\n\n// after\nconst results = await collection.query({\n  where: { $and: [condA, condB] },\n});","handlingStrategy":"type-guard","validationCode":"const isPlainObjectLike = (v: unknown): v is Record<string, unknown> => {\n  if (typeof v !== 'object' || v === null || Array.isArray(v)) return false;\n  const p = Object.getPrototypeOf(v);\n  return p === Object.prototype || p === null;\n};\nif (!isPlainObjectLike(where)) throw new Error('where must be a dict');","typeGuard":"const isWhereDict = (v: unknown): v is Record<string, unknown> =>\n  isPlainObjectLike(v); // WhereExpression instances also accepted by WhereExpression.from","tryCatchPattern":"try {\n  const results = await collection.query({ where });\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('Where input')) {\n    throw new Error(`Invalid where filter shape: ${JSON.stringify(where)}`);\n  }\n  throw e;\n}","preventionTips":["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: {...} } }"],"tags":["where","filter","input-validation","type-error","client-side"],"backgroundTag":"invalid-query-filter","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}