chroma-core/chroma · error · ValueError
$sub requires 'left' and 'right' fields
Error message
$sub requires 'left' and 'right' fields
What it means
The $sub rank operator in Chroma requires exactly two fields, 'left' and 'right', naming the minuend and subtrahend rank expressions. Rank.from_dict raises this ValueError when the payload is a dict but one or both of those keys are missing. Extra keys are ignored; only presence of both names matters.
Source
Thrown at chromadb/execution/expression/operator.py:775
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")
left = Rank.from_dict(sub_data["left"])
right = Rank.from_dict(sub_data["right"])
return left - right
elif op == "$mul":
ranks_data = data["$mul"]
if not isinstance(ranks_data, (list, tuple)):
raise TypeError(
f"$mul requires a list, got {type(ranks_data).__name__}"
)
if len(ranks_data) < 2:
raise ValueError(
f"$mul requires at least 2 ranks, got {len(ranks_data)}"
)
ranks = [Rank.from_dict(r) for r in ranks_data]
result = ranks[0]View on GitHub (pinned to aecdd12c8a)
Solutions
- Include both keys: {"$sub": {"left": <rank>, "right": <rank>}}
- If the right operand is optional in your logic, substitute {"$val": 0} instead of omitting the key
- Check 'left' in d['$sub'] and 'right' in d['$sub'] before calling Rank.from_dict
- Generate the dict via Python (left_rank - right_rank).to_dict() so keys are always correct
Example fix
# before
expr = {"$sub": {"left": knn_rank}}
# after
expr = {"$sub": {"left": knn_rank, "right": {"$val": 0}}} Defensive patterns
Strategy: validation
Validate before calling
sub = rank_expr.get("$sub")
if not (isinstance(sub, dict) and "left" in sub and "right" in sub):
raise ValueError(f"$sub requires 'left' and 'right': {rank_expr!r}") Type guard
def is_complete_sub_expr(d) -> bool:
return (isinstance(d, dict) and set(d) == {"$sub"}
and isinstance(d["$sub"], dict)
and {"left", "right"} <= set(d["$sub"])) 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
- Use exact key names 'left' and 'right' — no abbreviations
- When an operand is optional in your logic, substitute {"$val": 0} instead of omitting it
- Prefer (left - right).to_dict() so keys are generated by the library
When it happens
Trigger: Rank.from_dict({'$sub': {'left': {...}}}) with 'right' omitted, or keys renamed by a generator ('lhs'/'rhs', 'a'/'b', 'minuend'/'subtrahend').
Common situations: Hand-written JSON with typos or abbreviated key names; code that builds the dict dynamically and skips the second operand when it is None; partial copy-paste of an example expression.
Related errors
- $div requires 'left' and 'right' fields
- $sum requires at least 2 ranks, got {len(ranks_data)}
- $sub requires a dict with 'left' and 'right', got {type(sub_
- $mul requires a list, got {type(ranks_data).__name__}
- $mul requires at least 2 ranks, got {len(ranks_data)}
AI-assisted analysis of chroma-core/chroma@aecdd12c8a (2026-08-16).
Data as JSON: /api/errors/d47c43c9ddfb5166.
Report an issue: GitHub.