chroma-core/chroma · error · ChromaValueError

Expected operand for ${operator} to be a list of 'whereDocum

Error message

Expected operand for ${operator} to be a list of 'whereDocument' expressions, but got ${operand}

What it means

When the single top-level operator is $and or $or, its operand must be an array of whereDocument expressions (utils.ts:680-685). Passing an object, a string, or any non-array throws this ChromaValueError from validateWhereDocument before a request is sent. Each array element is subsequently validated recursively by the same function.

Source

Thrown at clients/new-js/packages/chromadb/src/utils.ts:682

    ![
      "$contains",
      "$not_contains",
      "$matches",
      "$not_matches",
      "$regex",
      "$not_regex",
      "$and",
      "$or",
    ].includes(operator)
  ) {
    throw new ChromaValueError(
      `Expected 'whereDocument' operator to be one of $contains, $not_contains, $matches, $not_matches, $regex, $not_regex, $and, or $or, but got ${operator}`,
    );
  }

  if (operator === "$and" || operator === "$or") {
    if (!Array.isArray(operand)) {
      throw new ChromaValueError(
        `Expected operand for ${operator} to be a list of 'whereDocument' expressions, but got ${operand}`,
      );
    }

    if (operand.length <= 1) {
      throw new ChromaValueError(
        `Expected 'whereDocument' operand for ${operator} to be a list with at least two 'whereDocument' expressions`,
      );
    }

    operand.forEach((item) => validateWhereDocument(item));
  }

  if (
    (operand === "$contains" ||
      operand === "$not_contains" ||
      operand === "$regex" ||
      operand === "$not_regex") &&

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Wrap the sub-clauses in an array: { $and: [{ $contains: 'a' }, { $not_contains: 'b' }] }
  2. Make sure every array element is itself a valid single-operator whereDocument object
  3. Rely on the WhereDocument type — { $and: WhereDocument[] } is enforced by the compiler

Example fix

// before
whereDocument: { $and: { $contains: 'a' } }

// after
whereDocument: { $and: [{ $contains: 'a' }, { $not_contains: 'b' }] }
Defensive patterns

Strategy: validation

Validate before calling

function isCompoundWhereDocument(w: Record<string, unknown>): boolean {
  const [op, val] = Object.entries(w)[0];
  if (op !== '$and' && op !== '$or') return true; // not compound, nothing to check here
  return Array.isArray(val);
}
if (whereDocument && !isCompoundWhereDocument(whereDocument)) {
  throw new TypeError('$and/$or require an array of whereDocument clauses');
}

Type guard

const isCompoundClause = (w: unknown): w is { $and: unknown[] } | { $or: unknown[] } =>
  typeof w === 'object' && w !== null &&
  (('$and' in w) || ('$or' in w)) && Array.isArray((w as Record<string, unknown>).$and ?? (w as Record<string, unknown>).$or);

Try / catch

try {
  await col.query({ queryTexts, whereDocument: { $and: clauses } });
} catch (e) {
  if (e instanceof Error && e.message.includes('list of')) {
    clauses = [clauses].flat(2); // normalize accidental object/scalar into an array and retry
  } else throw e;
}

Prevention

When it happens

Trigger: collection.query({ queryTexts: [...], whereDocument: { $and: { $contains: 'a' } } }) (nested object instead of array); { $or: 'text' }; { $and: 123 }.

Common situations: Assuming Mongo-style nested-object conjunctions; adding a second condition and wrapping clauses in braces instead of brackets.

Related errors


AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16). Data as JSON: /api/errors/a5f122234bf18bed. Report an issue: GitHub.