{"record":{"id":"12c04ea219abeedb","repo":"chroma-core/chroma","slug":"div-requires-a-dict-with-left-and-right-got","errorCode":null,"errorMessage":"$div requires a dict with 'left' and 'right', got {type(div_data).__name__}","messagePattern":"\\$div requires a dict with 'left' and 'right', got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"chromadb/execution/expression/operator.py","lineNumber":801,"sourceCode":"            if not isinstance(ranks_data, (list, tuple)):\n                raise TypeError(\n                    f\"$mul requires a list, got {type(ranks_data).__name__}\"\n                )\n            if len(ranks_data) < 2:\n                raise ValueError(\n                    f\"$mul 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 * r\n            return result\n\n        elif op == \"$div\":\n            div_data = data[\"$div\"]\n            if not isinstance(div_data, dict):\n                raise TypeError(\n                    f\"$div requires a dict with 'left' and 'right', got {type(div_data).__name__}\"\n                )\n            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\":","sourceCodeStart":783,"sourceCodeEnd":819,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/execution/expression/operator.py#L783-L819","documentation":"The $div rank operator models division of two rank expressions (e.g. normalizing a KNN score by a constant) and, like $sub, expects a dict with 'left' and 'right' keys rather than an operand list. Rank.from_dict raises this TypeError when the $div payload is not a dict — commonly a two-element list written in the $sum/$mul style.","triggerScenarios":"Rank.from_dict({'$div': [numerator, denominator]}) or {'$div': 10}, including nested occurrences inside a larger expression tree.","commonSituations":"Using the list payload convention for every arithmetic operator in generated JSON; hand-writing a normalization expression and guessing the shape; copying the $sum pattern when adding division.","solutions":["Encode division as {\"$div\": {\"left\": numerator, \"right\": denominator}}","Convert list-shaped input before sending: {'$div': {'left': pair[0], 'right': pair[1]}}","Build in Python as numerator / denominator (or rank / 10.0) and call .to_dict()","Guard with isinstance(expr['$div'], dict) before Rank.from_dict"],"exampleFix":"# before\nexpr = {\"$div\": [knn_rank, {\"$val\": 10.0}]}\n\n# after\nexpr = {\"$div\": {\"left\": knn_rank, \"right\": {\"$val\": 10.0}}}","handlingStrategy":"validation","validationCode":"def valid_div_expr(expr):\n    return (\n        isinstance(expr, dict) and set(expr) == {\"$div\"}\n        and isinstance(expr[\"$div\"], dict)\n    )\n\nif not valid_div_expr(rank_expr):\n    raise ValueError(f\"$div payload must be a dict with left/right, got {rank_expr!r}\")","typeGuard":"def is_div_expr(d) -> bool:\n    return (isinstance(d, dict) and set(d) == {\"$div\"}\n            and isinstance(d[\"$div\"], 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":["$div follows the $sub convention ({'left','right'}), not the list convention","Build normalization in Python: (rank / 10.0).to_dict()","Test serialization round-trips for every expression shape you emit"],"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"}