chroma-core/chroma · error · ChromaValueError

Expected 'where' value to be a string, number, boolean, or a

Error message

Expected 'where' value to be a string, number, boolean, or an operator expression, but got ${value}

What it means

For a field key (not $and/$or/$in/$nin), validateWhere accepts only string, number, boolean, or object values — 'object' meaning an operator expression like { $gte: 10 }. Any other typeof (undefined, function, bigint, symbol) throws ChromaValueError. The message interpolates the value itself, which can look odd for functions.

Source

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

  }

  if (Object.keys(where).length != 1) {
    throw new ChromaValueError(
      `Expected 'where' to have exactly one operator, but got ${
        Object.keys(where).length
      }`,
    );
  }

  Object.entries(where).forEach(([key, value]) => {
    if (
      key !== "$and" &&
      key !== "$or" &&
      key !== "$in" &&
      key !== "$nin" &&
      !["string", "number", "boolean", "object"].includes(typeof value)
    ) {
      throw new ChromaValueError(
        `Expected 'where' value to be a string, number, boolean, or an operator expression, but got ${value}`,
      );
    }

    if (key === "$and" || key === "$or") {
      if (Object.keys(value).length <= 1) {
        throw new ChromaValueError(
          `Expected 'where' value for $and or $or to be a list of 'where' expressions, but got ${value}`,
        );
      }

      value.forEach((w: Where) => validateWhere(w));
      return;
    }

    if (typeof value === "object") {
      if (Object.keys(value).length != 1) {
        throw new ChromaValueError(

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Strip undefined values before the call: Object.fromEntries(Object.entries(f).filter(([, v]) => v != null)).
  2. Only assign keys whose value is a scalar or a single-operator expression.
  3. Type the filter with Chroma's Where type so the compiler rejects bad shapes.

Example fix

// before
where: { genre: req.query.genre } // genre is undefined

// after
const entries = Object.entries({ genre: req.query.genre }).filter(([, v]) => v !== undefined);
const where = entries.length ? Object.fromEntries(entries) : undefined;
Defensive patterns

Strategy: type-guard

Validate before calling

const clean = Object.fromEntries(
  Object.entries(filter).filter(([, v]) => ['string', 'number', 'boolean', 'object'].includes(typeof v))
);
await collection.query({ queryTexts, where: clean });

Type guard

const isWhereValue = (v: unknown): v is string | number | boolean | object =>
  ['string', 'number', 'boolean', 'object'].includes(typeof v);

Try / catch

try {
  await collection.query({ queryTexts, where });
} catch (e) {
  if ((e as Error).message.includes('operator expression, but got')) {
    // strip undefined/function values from the where object and retry
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: where: { field: undefined } — building filters from optional request params without stripping undefined. where: { field: () => true }. A BigInt operand (typeof 'bigint').

Common situations: Optional filter params passed straight from an HTTP query object; defaulting missing filters to undefined instead of removing the key; storing computed predicates in the filter object.

Related errors


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