chroma-core/chroma · error · ValueError

$sum requires at least 2 ranks, got {len(ranks_data)}

Error message

$sum requires at least 2 ranks, got {len(ranks_data)}

What it means

Chroma's execution engine deserializes rank (reranking) expressions from JSON via Rank.from_dict. The $sum operator folds several rank expressions into one Sum, and the parser requires its payload to be a list with at least two rank dicts, because a Sum with fewer than two operands is meaningless (the serializer side only ever emits >= 2 operands after flattening). This ValueError fires when the $sum payload list has 0 or 1 elements.

Source

Thrown at chromadb/execution/expression/operator.py:758

                    f"$knn return_rank must be a boolean, got {type(return_rank).__name__}"
                )

            return Knn(
                query=query,
                key=key,
                limit=limit,
                default=knn_data.get("default"),
                return_rank=return_rank,
            )

        elif op == "$sum":
            ranks_data = data["$sum"]
            if not isinstance(ranks_data, (list, tuple)):
                raise TypeError(
                    f"$sum requires a list, got {type(ranks_data).__name__}"
                )
            if len(ranks_data) < 2:
                raise ValueError(
                    f"$sum requires at least 2 ranks, got {len(ranks_data)}"
                )

            ranks = [Rank.from_dict(r) for r in ranks_data]
            result = ranks[0]
            for r in ranks[1:]:
                result = result + r
            return result

        elif op == "$sub":
            sub_data = data["$sub"]
            if not isinstance(sub_data, dict):
                raise TypeError(
                    f"$sub requires a dict with 'left' and 'right', got {type(sub_data).__name__}"
                )
            if "left" not in sub_data or "right" not in sub_data:
                raise ValueError("$sub requires 'left' and 'right' fields")

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. If there is only one rank, drop the $sum wrapper and pass the rank dict itself (e.g. {'$knn': {...}} instead of {'$sum': [{'$knn': {...}}]})
  2. If building dynamically, branch on length: expr = ranks[0] if len(ranks) == 1 else {'$sum': ranks}
  3. Build expressions with the Python operator API (rank1 + rank2 ... then .to_dict()) instead of hand-writing operator dicts, so the serializer emits valid shapes
  4. Validate the $sum payload shape with a guard before calling Rank.from_dict or sending the query

Example fix

# before
ranks = [{"$knn": {"query": q, "return_rank": True}} for q in queries]  # may be length 1
expr = {"$sum": ranks}

# after
ranks = [{"$knn": {"query": q, "return_rank": True}} for q in queries]
expr = ranks[0] if len(ranks) == 1 else {"$sum": ranks}
Defensive patterns

Strategy: validation

Validate before calling

def valid_sum_expr(expr):
    return (
        isinstance(expr, dict) and set(expr) == {"$sum"}
        and isinstance(expr["$sum"], (list, tuple))
        and len(expr["$sum"]) >= 2
    )

if not valid_sum_expr(rank_expr):
    raise ValueError(f"invalid $sum expression: {rank_expr!r}")

Type guard

def is_sum_expr(d) -> bool:
    return (isinstance(d, dict) and set(d) == {"$sum"}
            and isinstance(d["$sum"], (list, tuple))
            and len(d["$sum"]) >= 2)

Try / catch

try:
    rank = Rank.from_dict(rank_expr)
except (TypeError, ValueError) as e:
    raise ValueError(f"invalid rank expression {rank_expr!r}: {e}") from e

Prevention

When it happens

Trigger: Calling Rank.from_dict({'$sum': [...]}) directly, or submitting a query whose rank expression contains {'$sum': []} or {'$sum': [<single rank dict>]}. Most often the list is built dynamically over a variable number of searches and collapses to one element at runtime.

Common situations: Hybrid/multi-query search code that fuses N KNN rankings with $sum where a filter reduces N to 1; hand-written rank-expression JSON that wraps a lone term in $sum 'for consistency'; test fixtures copied from a two-query example and trimmed to one.

Related errors


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