{"record":{"id":"f450e6df83ae8e94","repo":"chroma-core/chroma","slug":"max-requires-at-least-2-ranks-got-len-ranks-dat","errorCode":null,"errorMessage":"$max requires at least 2 ranks, got {len(ranks_data)}","messagePattern":"\\$max requires at least 2 ranks, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"chromadb/execution/expression/operator.py","lineNumber":842,"sourceCode":"                )\n            return Rank.from_dict(child_data).exp()\n\n        elif op == \"$log\":\n            child_data = data[\"$log\"]\n            if not isinstance(child_data, dict):\n                raise TypeError(\n                    f\"$log requires a rank dict, got {type(child_data).__name__}\"\n                )\n            return Rank.from_dict(child_data).log()\n\n        elif op == \"$max\":\n            ranks_data = data[\"$max\"]\n            if not isinstance(ranks_data, (list, tuple)):\n                raise TypeError(\n                    f\"$max requires a list, got {type(ranks_data).__name__}\"\n                )\n            if len(ranks_data) < 2:\n                raise ValueError(\n                    f\"$max requires at least 2 ranks, got {len(ranks_data)}\"\n                )\n\n            ranks = [Rank.from_dict(r) for r in ranks_data]\n            result = ranks[0]\n            for r in ranks[1:]:\n                result = result.max(r)\n            return result\n\n        elif op == \"$min\":\n            ranks_data = data[\"$min\"]\n            if not isinstance(ranks_data, (list, tuple)):\n                raise TypeError(\n                    f\"$min requires a list, got {type(ranks_data).__name__}\"\n                )\n            if len(ranks_data) < 2:\n                raise ValueError(\n                    f\"$min requires at least 2 ranks, got {len(ranks_data)}\"","sourceCodeStart":824,"sourceCodeEnd":860,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/execution/expression/operator.py#L824-L860","documentation":"$max combines at least two rank expressions via successive pairwise maximums, so Chroma's parser rejects a payload with fewer than two operands. This ValueError from Rank.from_dict fires when the $max list has 0 or 1 elements.","triggerScenarios":"Rank.from_dict({'$max': []}) or {'$max': [single_rank]} — e.g. a clamp built as max over a dynamic list of bounds where only one bound survives filtering.","commonSituations":"Clamping code that takes max over a configurable list of upper bounds and ends up with one; wrapping a lone operand 'for consistency'; fixtures trimmed from a two-operand example.","solutions":["Pass at least two operands, or drop the wrapper and pass the single rank dict directly","When clamping against a bound, always include both: {\"$max\": [rank, {\"$val\": bound}]}","Branch when building dynamically: expr = ranks[0] if len(ranks) == 1 else {'$max': ranks}","Validate operand count before deserialization"],"exampleFix":"# before\nexpr = {\"$max\": [knn_rank]}\n\n# after\nexpr = {\"$max\": [knn_rank, {\"$val\": 0.0}]}","handlingStrategy":"validation","validationCode":"def valid_max_expr(expr):\n    return (\n        isinstance(expr, dict) and set(expr) == {\"$max\"}\n        and isinstance(expr[\"$max\"], (list, tuple))\n        and len(expr[\"$max\"]) >= 2\n    )\n\nif not valid_max_expr(rank_expr):\n    raise ValueError(f\"$max needs >= 2 operands: {rank_expr!r}\")","typeGuard":"def is_max_expr(d) -> bool:\n    return (isinstance(d, dict) and set(d) == {\"$max\"}\n            and isinstance(d[\"$max\"], (list, tuple))\n            and len(d[\"$max\"]) >= 2)","tryCatchPattern":"try:\n    rank = Rank.from_dict(rank_expr)\nexcept (TypeError, ValueError) as e:\n    raise ValueError(f\"invalid rank expression {rank_expr!r}: {e}\") from e","preventionTips":["A clamp always has two sides: include the bound as {\"$val\": b} alongside the rank","Never wrap a lone operand in $max","Branch on operand count when clamps are built from configurable bound lists"],"tags":["chromadb","rank-expression","validation","deserialization","clamping"],"backgroundTag":"query-expression-validation","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}