chroma-core/chroma · error · ValueError
$min requires at least 2 ranks, got {len(ranks_data)}
Error message
$min requires at least 2 ranks, got {len(ranks_data)} What it means
$min combines at least two rank expressions via successive pairwise minimums, so Chroma's parser rejects payloads with fewer than two operands. This ValueError from Rank.from_dict fires when the $min list has 0 or 1 elements.
Source
Thrown at chromadb/execution/expression/operator.py:859
if len(ranks_data) < 2:
raise ValueError(
f"$max 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.max(r)
return result
elif op == "$min":
ranks_data = data["$min"]
if not isinstance(ranks_data, (list, tuple)):
raise TypeError(
f"$min requires a list, got {type(ranks_data).__name__}"
)
if len(ranks_data) < 2:
raise ValueError(
f"$min 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.min(r)
return result
else:
raise ValueError(f"Unknown rank operator: {op}")
# Arithmetic operators
def __add__(self, other: Union["Rank", float, int]) -> "Sum":
"""Addition: rank1 + rank2 or rank + value"""
other_rank = Val(other) if isinstance(other, (int, float)) else other
# Flatten if already Sum
if isinstance(self, Sum):View on GitHub (pinned to aecdd12c8a)
Solutions
- Pass at least two operands, or drop the wrapper and pass the single rank dict directly
- When capping against a bound, always include both: {"$min": [rank, {"$val": bound}]}
- Branch when building dynamically: expr = ranks[0] if len(ranks) == 1 else {'$min': ranks}
- Validate operand count before deserialization
Example fix
# before
expr = {"$min": [knn_rank]}
# after
expr = {"$min": [knn_rank, {"$val": 1.0}]} Defensive patterns
Strategy: validation
Validate before calling
def valid_min_expr(expr):
return (
isinstance(expr, dict) and set(expr) == {"$min"}
and isinstance(expr["$min"], (list, tuple))
and len(expr["$min"]) >= 2
)
if not valid_min_expr(rank_expr):
raise ValueError(f"$min needs >= 2 operands: {rank_expr!r}") Type guard
def is_min_expr(d) -> bool:
return (isinstance(d, dict) and set(d) == {"$min"}
and isinstance(d["$min"], (list, tuple))
and len(d["$min"]) >= 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
- A cap always has two sides: include the bound as {"$val": b}
- Pass a lone operand through unwrapped
- Validate bound lists built from config before folding them into $min
When it happens
Trigger: Rank.from_dict({'$min': []}) or {'$min': [single_rank]} — e.g. a cap built over a dynamic list of bounds where only one remains, or a lone operand wrapped needlessly.
Common situations: Configurable clamping where the bounds list collapses to one element; 'consistency' wrapping of a single term; trimmed test fixtures.
Related errors
- $max requires at least 2 ranks, got {len(ranks_data)}
- $sum requires at least 2 ranks, got {len(ranks_data)}
- $sub requires a dict with 'left' and 'right', got {type(sub_
- $sub requires 'left' and 'right' fields
- $mul requires a list, got {type(ranks_data).__name__}
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/20bf692ae8187792.
Report an issue: GitHub.