{"record":{"id":"982684555a51b03b","repo":"chroma-core/chroma","slug":"abs-requires-a-rank-dict-got-type-child-data","errorCode":null,"errorMessage":"$abs requires a rank dict, got {type(child_data).__name__}","messagePattern":"\\$abs requires a rank dict, got (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"chromadb/execution/expression/operator.py","lineNumber":814,"sourceCode":"            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\":\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                )","sourceCodeStart":796,"sourceCodeEnd":832,"githubUrl":"https://github.com/chroma-core/chroma/blob/aecdd12c8a891610db8653630b066b32ceb678b5/chromadb/execution/expression/operator.py#L796-L832","documentation":"$abs is a unary rank operator that takes exactly one nested rank expression (e.g. abs of a difference) and expects its payload to be a single rank dict. Rank.from_dict raises this TypeError when the $abs payload is not a dict — most commonly a bare number or a list wrapping the operand.","triggerScenarios":"Rank.from_dict({'$abs': 5}), {'$abs': [{'$val': 5}]}, or {'$abs': [knn_rank]} — any non-dict payload, at any nesting depth in the expression tree.","commonSituations":"Wrapping the operand in brackets 'to be safe' because list operators ($sum/$mul) take lists; passing a literal number directly; hand-authored JSON that abbreviates {'$val': 5} to 5.","solutions":["Pass one unwrapped rank dict: {\"$abs\": {\"$val\": 5}} or {\"$abs\": {\"$sub\": {...}}}","Wrap literals in $val: use {\"$abs\": {\"$val\": 5}} for abs of a constant","Build in Python as abs(rank_expr).to_dict()","Guard: isinstance(expr['$abs'], dict) before deserialization"],"exampleFix":"# before\nexpr = {\"$abs\": [{\"$sub\": {\"left\": a, \"right\": b}}]}\n\n# after\nexpr = {\"$abs\": {\"$sub\": {\"left\": a, \"right\": b}}}","handlingStrategy":"validation","validationCode":"def valid_abs_expr(expr):\n    return (\n        isinstance(expr, dict) and set(expr) == {\"$abs\"}\n        and isinstance(expr[\"$abs\"], dict)\n    )\n\nif not valid_abs_expr(rank_expr):\n    raise ValueError(f\"$abs payload must be a single rank dict: {rank_expr!r}\")","typeGuard":"def is_abs_expr(d) -> bool:\n    return (isinstance(d, dict) and set(d) == {\"$abs\"}\n            and isinstance(d[\"$abs\"], 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":["Unary operators ($abs/$exp/$log) take one bare rank dict — no list wrapping, no bare literals","Wrap constants with $val before nesting: {\"$abs\": {\"$val\": 5}}","Use abs(rank).to_dict() in Python instead of hand-writing the dict"],"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"}