{"record":{"id":"1f5fd49cc019e178","repo":"chroma-core/chroma","slug":"expected-where-to-be-a-non-empty-object","errorCode":null,"errorMessage":"Expected where to be a non-empty object","messagePattern":"Expected where to be a non-empty object","errorType":"validation","errorClass":"ChromaValueError","httpStatus":null,"severity":"error","filePath":"clients/new-js/packages/chromadb/src/utils.ts","lineNumber":535,"sourceCode":"export const validateMaxBatchSize = (\n  recordSetLength: number,\n  maxBatchSize: number,\n) => {\n  if (recordSetLength > maxBatchSize) {\n    throw new ChromaValueError(\n      `Record set length ${recordSetLength} exceeds max batch size ${maxBatchSize}`,\n    );\n  }\n};\n\n/**\n * Validates a where clause for metadata filtering.\n * @param where - Where clause object to validate\n * @throws ChromaValueError if the where clause is malformed\n */\nexport const validateWhere = (where: Where) => {\n  if (typeof where !== \"object\") {\n    throw new ChromaValueError(\"Expected where to be a non-empty object\");\n  }\n\n  if (Object.keys(where).length != 1) {\n    throw new ChromaValueError(\n      `Expected 'where' to have exactly one operator, but got ${\n        Object.keys(where).length\n      }`,\n    );\n  }\n\n  Object.entries(where).forEach(([key, value]) => {\n    if (\n      key !== \"$and\" &&\n      key !== \"$or\" &&\n      key !== \"$in\" &&\n      key !== \"$nin\" &&\n      ![\"string\", \"number\", \"boolean\", \"object\"].includes(typeof value)\n    ) {","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/clients/new-js/packages/chromadb/src/utils.ts#L517-L553","documentation":"validateWhere rejects a where argument whose typeof is not 'object'. This is a type gate: strings, numbers, booleans, and other non-object filters throw ChromaValueError immediately, client-side. Subsequent checks require exactly one top-level key, so the where clause must be a single-key operator object.","triggerScenarios":"collection.query({ where: 'genre = sci-fi' }) — passing a raw SQL-ish string. where: 123. Spreading a string variable into the where option by mistake.","commonSituations":"Translating SQL or Mongo-like filter strings into Chroma's structured filters; a filter builder returning a primitive when no criteria exist; passing a serialized JSON string instead of a parsed object.","solutions":["Pass a structured object: where: { genre: 'sci-fi' } or where: { $and: [ ... ] }.","Parse JSON strings before use: where: JSON.parse(raw).","Omit the where option entirely when no filtering is needed — do not pass a primitive placeholder."],"exampleFix":"// before\nawait collection.query({ queryTexts: ['x'], where: 'genre = sci-fi' });\n\n// after\nawait collection.query({ queryTexts: ['x'], where: { genre: 'sci-fi' } });","handlingStrategy":"type-guard","validationCode":"if (where !== undefined && (typeof where !== 'object' || where === null)) {\n  throw new TypeError('where must be an object like { field: value } or { $and: [...] }');\n}\nawait collection.query({ queryTexts, where });","typeGuard":"const isWhere = (w: unknown): w is Record<string, unknown> =>\n  typeof w === 'object' && w !== null && !Array.isArray(w);","tryCatchPattern":"try {\n  await collection.query({ queryTexts, where });\n} catch (e) {\n  if ((e as Error).message.includes('where to be a non-empty object')) {\n    // fix the where shape to an object, or omit it and retry\n  } else {\n    throw e;\n  }\n}","preventionTips":["Build filters as structured objects, never strings.","Parse JSON filter payloads before passing them.","Omit the where option when no filtering is needed."],"tags":["where-filter","validation","query","javascript"],"backgroundTag":"invalid-where-clause","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}