chroma-core/chroma · error · TypeError

$sum requires a list, got {type(ranks_data).__name__}

Error message

$sum requires a list, got {type(ranks_data).__name__}

What it means

$sum combines rank expressions and takes a list of at least two rank dicts: {'$sum': [rank1, rank2, ...]}. Passing anything that is not a list/tuple - a dict or bare value - raises TypeError before element validation. $sum/$mul/$max/$min are n-ary list-shaped operators, while $sub/$div take {'left', 'right'} dicts.

Source

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

            return_rank = knn_data.get("return_rank", False)
            if not isinstance(return_rank, bool):
                raise TypeError(
                    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__}"

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Use a list with >= 2 rank dicts: {'$sum': [{'$val': 1}, {'$knn': {...}}]}.
  2. For two-term subtraction/division switch operators: {'$sub': {'left': ..., 'right': ...}} or '$div'.
  3. For a single term, drop the wrapper - the child rank alone is the expression.

Example fix

# before
Search(rank={'$sum': {'left': {'$val': 1}, 'right': {'$val': 2}}})   # -> TypeError: got dict

# after
Search(rank={'$sum': [{'$val': 1}, {'$val': 2}]})
# two-term binary alternative
Search(rank={'$sub': {'left': {'$val': 1}, 'right': {'$val': 2}}})
Defensive patterns

Strategy: type-guard

Validate before calling

def rank_sum(*terms):
    if len(terms) < 2:
        raise ValueError('$sum needs at least 2 ranks')
    return {'$sum': list(terms)}

Search(rank=rank_sum({'$val': 1}, {'$knn': {'query': emb}}))

Type guard

def is_nary_rank_payload(arg) -> bool:
    return (
        isinstance(arg, (list, tuple))
        and len(arg) >= 2
        and all(isinstance(t, dict) for t in arg)
    )

Prevention

When it happens

Trigger: Search(rank={'$sum': {'left': {...}, 'right': {...}}}) - using $sub's shape with $sum; {'$sum': {'$val': 1}} trying to 'sum' a single term; {'$sum': 'expr'} passing a string.

Common situations: Mixing up operator arities when hand-writing expressions; template code emitting the same payload shape for every operator; building weighted scores and pairing $sum with a dict by analogy to $sub.

Related errors


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