{"record":{"id":"c8f96d976c6f0a30","repo":"chroma-core/chroma","slug":"and-must-be-a-non-empty-array","errorCode":null,"errorMessage":"$and must be a non-empty array","messagePattern":"\\$and must be a non-empty array","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/execution/expression/where.ts","lineNumber":165,"sourceCode":"  [\"$in\", (key, value) => new ComparisonWhere(key, \"$in\", value)],\n  [\"$nin\", (key, value) => new ComparisonWhere(key, \"$nin\", value)],\n  [\"$contains\", (key, value) => new ComparisonWhere(key, \"$contains\", value)],\n  [\n    \"$not_contains\",\n    (key, value) => new ComparisonWhere(key, \"$not_contains\", value),\n  ],\n  [\"$regex\", (key, value) => new ComparisonWhere(key, \"$regex\", value)],\n  [\"$not_regex\", (key, value) => new ComparisonWhere(key, \"$not_regex\", value)],\n]);\n\nconst parseWhereDict = (data: Record<string, unknown>): WhereExpression => {\n  if (\"$and\" in data) {\n    if (Object.keys(data).length !== 1) {\n      throw new Error(\"$and cannot be combined with other keys\");\n    }\n    const rawConditions = data[\"$and\"];\n    if (!Array.isArray(rawConditions) || rawConditions.length === 0) {\n      throw new TypeError(\"$and must be a non-empty array\");\n    }\n    const conditions = rawConditions.map((item, index) => {\n      const expr = WhereExpression.from(item as WhereInput);\n      if (!expr) {\n        throw new TypeError(`Invalid where clause at index ${index}`);\n      }\n      return expr;\n    });\n    if (conditions.length === 1) {\n      return conditions[0];\n    }\n    return conditions\n      .slice(1)\n      .reduce(\n        (acc, condition) => AndWhere.combine(acc, condition),\n        conditions[0],\n      );\n  }","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/execution/expression/where.ts#L147-L183","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst where = { $and: conditions.filter(enabled) }; // may be []\n\n// after\nconst clauses = conditions.filter(enabled);\nconst where = clauses.length > 1 ? { $and: clauses } : clauses[0];","handlingStrategy":"validation","validationCode":"const clauses = rawClauses.filter(c => c != null);\nif (clauses.length === 0) throw new Error('no where clauses to combine');\nconst where = clauses.length > 1 ? { $and: clauses } : clauses[0];","typeGuard":"const isNonEmptyClauseArray = (v: unknown): v is object[] =>\n  Array.isArray(v) && v.length > 0;","tryCatchPattern":"try {\n  const results = await collection.query({ where });\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes('non-empty array')) {\n    return collection.query({}); // drop the empty filter\n  }\n  throw e;\n}","preventionTips":["$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"],"tags":["where","and","empty-array","query-filter","input-validation"],"backgroundTag":"invalid-query-filter","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}