chroma-core/chroma · error · TypeError

You must provide either queryEmbeddings or queryTexts

Error message

You must provide either queryEmbeddings or queryTexts

What it means

Aggregate.from_dict() (operator.py:1415-1418) requires the aggregate dict to contain exactly one operator entry; two or more raise ValueError with the count. An aggregation strategy is a single choice — keep-k-minimum OR keep-k-maximum — so {"$min_k": {...}, "$max_k": {...}} is ambiguous and rejected rather than guessed. The count is taken on the whole dict (len(data)), and the sole entry must then be '$min_k' or '$max_k' (operator.py:1420-1429).

Source

Thrown at clients/js/packages/chromadb-core/src/Collection.ts:300

    queryTexts,
    queryEmbeddings,
    ids,
  }: QueryRecordsParams): Promise<MultiQueryResponse> {
    await this.client.init();

    let embeddings: number[][] = [];

    // If queryEmbeddings is provided, use it
    if (queryEmbeddings) {
      embeddings = toArrayOfArrays(queryEmbeddings);
    }
    // If queryTexts is provided, use it to generate queryEmbeddings
    else if (queryTexts) {
      embeddings = await this.embeddingFunction.generate(toArray(queryTexts));
    }

    if (embeddings.length === 0) {
      throw new TypeError(
        "You must provide either queryEmbeddings or queryTexts",
      );
    }

    let filter_ids: string[] | null = null;
    if (ids) {
      filter_ids = toArray(ids);
    }

    const resp = await this.client.api.collectionQuery(
      this.client.tenant,
      this.client.database,
      this.id,
      nResults,
      undefined,
      {
        query_embeddings: embeddings,
        ids: filter_ids,

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Keep exactly one operator key: {"$min_k": {"keys": ["#score"], "k": 3}}.
  2. If you merged configs, delete the losing operator so only one entry remains.
  3. Cannot combine min and max in one aggregate — run two Search queries if you need both orderings.
  4. Keep metadata/version keys out of the aggregate object; only the operator entry belongs there.

Example fix

// before
aggregate = {"$min_k": {"keys": ["#score"], "k": 3}, "$max_k": {"keys": ["#score"], "k": 3}}
# ValueError: Aggregate dict must contain exactly one operator, got 2

# after
aggregate = {"$min_k": {"keys": ["#score"], "k": 3}}
Defensive patterns

Strategy: validation

Validate before calling

def aggregate_single_op(payload: dict) -> bool:
    return isinstance(payload, dict) and len(payload) == 1

Type guard

def is_single_operator_aggregate(v: Any) -> TypeGuard[Dict[str, Dict[str, Any]]]:
    return (
        isinstance(v, dict)
        and len(v) == 1
        and next(iter(v)) in {"$min_k", "$max_k"}
        and isinstance(next(iter(v.values())), dict)
    )

Try / catch

try:
    Aggregate.from_dict(agg)
except ValueError as e:
    if "exactly one operator" in str(e):
        ops = [k for k in agg if k in ("$min_k", "$max_k")]
        agg = {ops[0]: agg[ops[0]]}  # keep the first real operator
    else:
        raise

Prevention

When it happens

Trigger: {"$min_k": {...}, "$max_k": {...}} — trying to apply both orderings; entries sharing the dict with metadata like {"$min_k": {...}, "version": 2}; merging two aggregate configs with dict.update() so both operators survive; a copy-paste artifact leaving a duplicated operator block.

Common situations: Config systems that merge user overrides over defaults and end up with both operators; authors assuming multiple aggregations compose (they do not — pick one ordering per GroupBy); payloads decorated with extra bookkeeping keys inside the aggregate object; hand-editing examples by adding instead of replacing an operator.

Related errors


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