{"record":{"id":"d6c172bbace8b66e","repo":"chroma-core/chroma","slug":"log-requires-a-rank-dict-got-type-child-data","errorCode":null,"errorMessage":"$log requires a rank dict, got {type(child_data).__name__}","messagePattern":"\\$log requires a rank dict, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"chromadb/execution/expression/operator.py","lineNumber":830,"sourceCode":"            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                )\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:]:","sourceCodeStart":812,"sourceCodeEnd":848,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/execution/expression/operator.py#L812-L848","documentation":"$log is a unary rank operator applying the logarithm to one nested rank expression (the counterpart of $exp), and its payload must be a single rank dict. Rank.from_dict raises this TypeError when the $log payload is not a dict — typically a bare number or a one-element list.","triggerScenarios":"Rank.from_dict({'$log': 10}), {'$log': [rank_dict]}, or the same nested inside $sum/$mul trees being deserialized.","commonSituations":"Score-normalization pipelines that log-transform raw scores, with the operand accidentally list-wrapped or the literal passed without $val; JSON from generators that uniformly list-wrap all operands.","solutions":["Pass one unwrapped rank dict: {\"$log\": {\"$val\": 10}} or {\"$log\": knn_dict}","Use $val to wrap literals before nesting","Build in Python as rank_expr.log().to_dict()","Guard: isinstance(expr['$log'], dict) before Rank.from_dict"],"exampleFix":"# before\nexpr = {\"$log\": [knn_rank]}\n\n# after\nexpr = {\"$log\": knn_rank}","handlingStrategy":"validation","validationCode":"def valid_log_expr(expr):\n    return (\n        isinstance(expr, dict) and set(expr) == {\"$log\"}\n        and isinstance(expr[\"$log\"], dict)\n    )\n\nif not valid_log_expr(rank_expr):\n    raise ValueError(f\"$log payload must be a single rank dict: {rank_expr!r}\")","typeGuard":"def is_log_expr(d) -> bool:\n    return (isinstance(d, dict) and set(d) == {\"$log\"}\n            and isinstance(d[\"$log\"], 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":["$log takes one bare rank dict; do not list-wrap the operand","Wrap literals in $val first","Prefer rank_expr.log().to_dict() so the payload shape is always valid"],"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"}