chroma-core/chroma · error · ChromaValueError

Expected 'whereDocument' operator to be one of $contains, $n

Error message

Expected 'whereDocument' operator to be one of $contains, $not_contains, $matches, $not_matches, $regex, $not_regex, $and, or $or, but got ${operator}

What it means

validateWhereDocument accepts only eight operators as the single top-level key: $contains, $not_contains, $matches, $not_matches, $regex, $not_regex, $and, $or (utils.ts:663-678). Any other key — metadata-where operators like $eq/$gt/$ne, un-prefixed names, or typos — throws this ChromaValueError client-side before a request is made. Document filters are text-matching operators; field-based operators belong to the separate `where` clause.

Source

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

    throw new ChromaValueError(
      `Expected 'whereDocument' to have exactly one operator, but got ${whereDocument}`,
    );
  }

  const [operator, operand] = Object.entries(whereDocument)[0];
  if (
    ![
      "$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));

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Use one of the eight documented document operators; for exact-text matching use { $regex: '^exact$' } instead of $eq
  2. Use the `where` parameter (not whereDocument) when filtering on metadata fields and values
  3. Check the exported WhereDocument type — the compiler enumerates the legal keys

Example fix

// before
await col.get({ whereDocument: { $eq: 'hello' } });

// after
await col.get({ whereDocument: { $regex: '^hello$' } });
Defensive patterns

Strategy: validation

Validate before calling

const DOC_OPERATORS = ['$contains', '$not_contains', '$matches', '$not_matches', '$regex', '$not_regex', '$and', '$or'];
const op = whereDocument && Object.keys(whereDocument)[0];
if (op !== undefined && !DOC_OPERATORS.includes(op)) {
  throw new Error(`unsupported whereDocument operator: ${op}; use one of ${DOC_OPERATORS.join(', ')}`);
}

Type guard

const DOC_OPS = ['$contains', '$not_contains', '$matches', '$not_matches', '$regex', '$not_regex', '$and', '$or'];
const hasDocumentOperator = (w: unknown): w is { [k: string]: unknown } =>
  typeof w === 'object' && w !== null && DOC_OPS.includes(Object.keys(w)[0]);

Try / catch

try {
  await col.get({ whereDocument });
} catch (e) {
  if (e instanceof Error && e.message.includes("whereDocument' operator to be one of")) {
    // map the bad operator to a legal one (e.g. $eq -> { $regex: `^${value}$` })
  } else throw e;
}

Prevention

When it happens

Trigger: collection.get({ whereDocument: { $eq: 'text' } }); whereDocument: { contains: 'x' } (missing $); { $matchs: 'x' } (typo); reusing a metadata `where` clause object as whereDocument in get/query/delete.

Common situations: Copy-pasting from `where` filter examples (those use $eq/$ne/$gt/$lte/$in/$nin); assuming Mongo-style operator syntax; older Chroma docs that only documented $contains.

Related errors


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