chroma-core/chroma · error · ValueError

Rank dict cannot be empty

Error message

Rank dict cannot be empty

What it means

An empty dict is not a valid rank expression: Rank.from_dict({}) raises ValueError because there is no operator key to dispatch. Every rank node must carry exactly one $-prefixed operator, so {} almost always means an absent optional rank was forwarded anyway, or a nested operand is empty.

Source

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

        Supports operators:
        - {"$val": number} -> Val(number)
        - {"$knn": {...}} -> Knn(...)
        - {"$sum": [ranks]} -> rank1 + rank2 + ...
        - {"$sub": {"left": ..., "right": ...}} -> left - right
        - {"$mul": [ranks]} -> rank1 * rank2 * ...
        - {"$div": {"left": ..., "right": ...}} -> left / right
        - {"$abs": rank} -> abs(rank)
        - {"$exp": rank} -> rank.exp()
        - {"$log": rank} -> rank.log()
        - {"$max": [ranks]} -> rank1.max(rank2).max(rank3)...
        - {"$min": [ranks]} -> rank1.min(rank2).min(rank3)...
        """
        if not isinstance(data, dict):
            raise TypeError(f"Expected dict for Rank, got {type(data).__name__}")

        if not data:
            raise ValueError("Rank dict cannot be empty")

        if len(data) != 1:
            raise ValueError(
                f"Rank dict must contain exactly one operator, got {len(data)}"
            )

        op = next(iter(data.keys()))

        if op == "$val":
            value = data["$val"]
            if not isinstance(value, (int, float)):
                raise TypeError(f"$val requires a number, got {type(value).__name__}")
            return Val(value)

        elif op == "$knn":
            knn_data = data["$knn"]
            if not isinstance(knn_data, dict):
                raise TypeError(f"$knn requires a dict, got {type(knn_data).__name__}")

View on GitHub (pinned to aecdd12c8a)

Solutions

  1. Pass rank=None to disable ranking.
  2. Use rank_cfg or None instead of {} when the config may be missing.
  3. When building trees programmatically, never emit a node whose operands are absent.

Example fix

# before
rank_cfg = user_params.get('rank', {})   # missing -> {}
Search(rank=rank_cfg)                     # -> ValueError: cannot be empty

# after
rank_cfg = user_params.get('rank') or None  # {} also becomes None
Search(rank=rank_cfg)
Defensive patterns

Strategy: validation

Validate before calling

rank_cfg = request.get('rank') or None   # {} becomes None
Search(rank=rank_cfg)

Type guard

def is_valid_rank_dict(node) -> bool:
    return isinstance(node, dict) and len(node) == 1

Prevention

When it happens

Trigger: Search(rank={}); Rank.from_dict({}); nested empties like {'$sum': [{}, {'$val': 1}]} where the empty child recurses into Rank.from_dict({}).

Common situations: Optional rank config defaulted with {} (user_cfg.get('rank', {})) and passed unconditionally; templating that renders an empty expression when a variable is missing; 'clearing' a rank by assigning {} instead of None.

Related errors


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