chroma-core/chroma · error · TypeError
Expected dict for Rank, got {type(data).__name__}
Error message
Expected dict for Rank, got {type(data).__name__} What it means
Rank.from_dict is the recursive parser for rank expressions ($val, $knn, $sum, ...) and requires every node, including nested operands, to be a dict with exactly one operator key. This TypeError fires when a non-dict reaches the parser - most often a bare number inside a list operand, because from_dict recurses via [Rank.from_dict(r) for r in ranks_data] (operator.py:762). Note Search(rank=0.5) is rejected earlier by plan.py:114 with a different message; primitives must be wrapped as {'$val': ...}.
Source
Thrown at chromadb/execution/expression/operator.py:671
@staticmethod
def from_dict(data: Dict[str, Any]) -> "Rank":
"""Create Rank expression from dictionary.
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":View on GitHub (pinned to aecdd12c8a)
Solutions
- Wrap every constant operand: {'$val': 0.5} instead of 0.5.
- Use the class API where composition is natural: Search(rank=Val(0.5) + Knn(query=[...]))) - arithmetic operators are overloaded.
- If trees arrive serialized, validate each node is a dict before parsing.
Example fix
# before
Search(rank={'$sum': [0.5, 0.3]}) # -> TypeError: got float
# after
Search(rank={'$sum': [{'$val': 0.5}, {'$val': 0.3}]})
# or use the classes
from chromadb.execution.expression.operator import Knn, Val
Search(rank=Val(0.5) + Val(0.3)) Defensive patterns
Strategy: type-guard
Validate before calling
def wrap_constants(node):
'''Recursively wrap bare numbers as {'$val': n} so Rank.from_dict accepts them.'''
if isinstance(node, (int, float)) and not isinstance(node, bool):
return {'$val': node}
if isinstance(node, list):
return [wrap_constants(n) for n in node]
if isinstance(node, dict):
return {k: wrap_constants(v) for k, v in node.items()}
return node
Search(rank=wrap_constants(rank_cfg)) Type guard
def is_rank_node(node) -> bool:
return (
isinstance(node, dict)
and len(node) == 1
and next(iter(node), '').startswith('$')
) Try / catch
try:
Search(rank=rank_cfg)
except (TypeError, ValueError) as e:
raise ValueError(f'invalid rank expression: {e}') from e Prevention
- Prefer Knn/Val objects with overloaded +, -, *, / over hand-built dicts.
- Every rank operand is itself a rank dict - constants need {'$val': ...}.
- Add a fixture test for each rank tree you ship; the recursion makes mistakes easy.
When it happens
Trigger: Rank.from_dict(0.5) or Rank.from_dict('$val') directly; {'$sum': [0.5, 0.3]} where operands recurse into Rank.from_dict(0.5); {'$abs': -0.5}; serialized rank trees where a node decoded to a scalar.
Common situations: Hand-writing rank expressions with bare numeric operands; converting formula code (a + b) into dicts without wrapping constants; machine-generated trees that collapse single-operator dicts to their value.
Related errors
- $sum requires a list, got {type(ranks_data).__name__}
- Rank dict cannot be empty
- Rank dict must contain exactly one operator, got {len(data)}
- $val requires a number, got {type(value).__name__}
- $knn requires a dict, got {type(knn_data).__name__}
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/97d386e825cc39a3.
Report an issue: GitHub.