{"record":{"id":"9da10d28518ee2ed","repo":"chroma-core/chroma","slug":"exp-requires-a-rank-dict-got-type-child-data","errorCode":null,"errorMessage":"$exp requires a rank dict, got {type(child_data).__name__}","messagePattern":"\\$exp requires a rank dict, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"chromadb/execution/expression/operator.py","lineNumber":822,"sourceCode":"            if \"left\" not in div_data or \"right\" not in div_data:\n                raise ValueError(\"$div requires 'left' and 'right' fields\")\n\n            left = Rank.from_dict(div_data[\"left\"])\n            right = Rank.from_dict(div_data[\"right\"])\n            return left / right\n\n        elif op == \"$abs\":\n            child_data = data[\"$abs\"]\n            if not isinstance(child_data, dict):\n                raise TypeError(\n                    f\"$abs requires a rank dict, got {type(child_data).__name__}\"\n                )\n            return abs(Rank.from_dict(child_data))\n\n        elif op == \"$exp\":\n            child_data = data[\"$exp\"]\n            if not isinstance(child_data, dict):\n                raise TypeError(\n                    f\"$exp requires a rank dict, got {type(child_data).__name__}\"\n                )\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                )","sourceCodeStart":804,"sourceCodeEnd":840,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/execution/expression/operator.py#L804-L840","documentation":"$exp is a unary rank operator applying the exponential function to one nested rank expression, and Chroma's parser expects its payload to be a single rank dict (as produced by Rank.exp().to_dict()). Rank.from_dict raises this TypeError when the $exp payload is not a dict — e.g. a bare number or a single-element list.","triggerScenarios":"Rank.from_dict({'$exp': 2.0}) or {'$exp': [rank_dict]} anywhere in a deserialized rank expression tree.","commonSituations":"Hand-written score-transform expressions for boosting (exp of a weighted sum) where the operand is wrapped in a list like $sum operands, or a literal is passed without $val; JSON produced by templating code unfamiliar with the unary-operator shape.","solutions":["Pass one unwrapped rank dict: {\"$exp\": {\"$val\": 2.0}} or {\"$exp\": {\"$mul\": [...]}}","Wrap bare numbers in $val first","Build in Python as rank_expr.exp().to_dict()","Guard: isinstance(expr['$exp'], dict) before Rank.from_dict"],"exampleFix":"# before\nexpr = {\"$exp\": [{\"$mul\": [knn, {\"$val\": 2.0}]}]}\n\n# after\nexpr = {\"$exp\": {\"$mul\": [knn, {\"$val\": 2.0}]}}","handlingStrategy":"validation","validationCode":"def valid_exp_expr(expr):\n    return (\n        isinstance(expr, dict) and set(expr) == {\"$exp\"}\n        and isinstance(expr[\"$exp\"], dict)\n    )\n\nif not valid_exp_expr(rank_expr):\n    raise ValueError(f\"$exp payload must be a single rank dict: {rank_expr!r}\")","typeGuard":"def is_exp_expr(d) -> bool:\n    return (isinstance(d, dict) and set(d) == {\"$exp\"}\n            and isinstance(d[\"$exp\"], dict))","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":["Treat $exp as unary: exactly one nested rank dict, never a list or literal","Build boosts in Python: weighted.exp().to_dict()","Keep a round-trip test covering unary operators"],"tags":["chromadb","rank-expression","validation","deserialization","type-error"],"backgroundTag":"query-expression-validation","analyzedSha":"aecdd12c8a891610db8653630b066b32ceb678b5","analyzedAt":"2026-08-16T21:53:27.228Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}