chroma-core/chroma · error · ChromaValueError

Expected operand value to be an array for ${operator}, but g

Error message

Expected operand value to be an array for ${operator}, but got ${operand}

What it means

$in and $nin require their operand to be an array; validateWhere throws when it is not. A scalar, object, or string value for these set-membership operators fails the Array.isArray check client-side. Wrap the value(s) in a list before the call.

Source

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

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

      const [operator, operand] = Object.entries(value)[0];

      if (
        ["$gt", "$gte", "$lt", "$lte"].includes(operator) &&
        typeof operand !== "number"
      ) {
        throw new ChromaValueError(
          `Expected operand value to be a number for ${operator}, but got ${typeof operand}`,
        );
      }

      if (["$in", "$nin"].includes(operator) && !Array.isArray(operand)) {
        throw new ChromaValueError(
          `Expected operand value to be an array for ${operator}, but got ${operand}`,
        );
      }

      if (
        ["$contains", "$not_contains"].includes(operator) &&
        !["string", "number", "boolean"].includes(typeof operand)
      ) {
        throw new ChromaValueError(
          `Expected operand value to be a string, number, or boolean for ${operator}, but got ${typeof operand}`,
        );
      }

      if (
        ![
          "$gt",
          "$gte",
          "$lt",

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Always wrap: { $in: ['sci-fi'] }.
  2. Normalize inputs: const list = Array.isArray(v) ? v : [v].
  3. Use $eq for exact single matches instead of $in with a scalar.

Example fix

// before
where: { genre: { $in: selectedGenre } } // selectedGenre = 'sci-fi'

// after
where: { genre: { $in: Array.isArray(selectedGenre) ? selectedGenre : [selectedGenre] } }
Defensive patterns

Strategy: validation

Validate before calling

const toList = (v) => Array.isArray(v) ? v : [v];
await collection.query({ queryTexts, where: { genre: { $in: toList(selected) } } });

Type guard

const isInOperand = (v: unknown): v is unknown[] => Array.isArray(v);

Try / catch

try {
  await collection.query({ queryTexts, where });
} catch (e) {
  if ((e as Error).message.includes('to be an array for')) {
    // wrap the scalar in [ ] and retry
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: where: { genre: { $in: 'sci-fi' } } — single value not wrapped. { $nin: { genre: 'x' } }. A variable that is sometimes scalar: { $in: selected } where selected = 'sci-fi'.

Common situations: Single-select UIs producing one value where the filter template expects a list; API params accepting both scalar and array forms; copy-pasting $eq syntax into $in.

Related errors


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