{"record":{"id":"ddbc81a3231d3896","repo":"pandas-dev/pandas","slug":"invalid-binary-operator-op-r-valid-operators-ar","errorCode":null,"errorMessage":"Invalid binary operator {op!r}, valid operators are {keys}","messagePattern":"Invalid binary operator (.+?), valid operators are (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"pandas/core/computation/ops.py","lineNumber":363,"sourceCode":"    lhs : Term or Op\n    rhs : Term or Op\n    \"\"\"\n\n    def __init__(self, op: str, lhs, rhs) -> None:\n        super().__init__(op, (lhs, rhs))\n        self.lhs = lhs\n        self.rhs = rhs\n\n        self._disallow_scalar_only_bool_ops()\n\n        self.convert_values()\n\n        try:\n            self.func = _binary_ops_dict[op]\n        except KeyError as err:\n            # has to be made a list for python3\n            keys = list(_binary_ops_dict.keys())\n            raise ValueError(\n                f\"Invalid binary operator {op!r}, valid operators are {keys}\"\n            ) from err\n\n    def __call__(self, env):\n        \"\"\"\n        Recursively evaluate an expression in Python space.\n\n        Parameters\n        ----------\n        env : Scope\n\n        Returns\n        -------\n        object\n            The result of an evaluated expression.\n        \"\"\"\n        # recurse over the left/right nodes\n        left = self.lhs(env)","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/pandas-dev/pandas/blob/71959b8cb9b2459c16e14b34f28b178ccfe14735/pandas/core/computation/ops.py#L345-L381","documentation":"Raised by BinOp.__init__ in pandas.core.computation.ops when the operator string supplied to BinOp is absent from _binary_ops_dict (the union of comparison, boolean, and arithmetic operator maps). The dict is keyed by CMP_OPS_SYMS, BOOL_OPS_SYMS, and ARITH_OPS_SYMS. The error is a ValueError and re-raises from the underlying KeyError. In normal use the AST parser only ever emits known operators, so this is essentially an internal invariant violation rather than something a user expression produces.","triggerScenarios":"Directly constructing ops.BinOp with an op string outside the supported sets (e.g. BinOp('^', lhs, rhs)), or a third-party parser/engine that hands pandas an unrecognized operator token. Standard pd.eval/df.query expressions cannot reach this branch because the grammar rejects unknown tokens earlier.","commonSituations":"Custom subclasses or monkey-patches of the eval machinery, experimental engines, or passing bitwise XOR '^' / '@' / other tokens through internal APIs. Extremely rare from public user input.","solutions":["If you are calling BinOp directly, restrict op to one of CMP_OPS_SYMS, BOOL_OPS_SYMS, or ARITH_OPS_SYMS ('>','<','>=','<=','==','!=','in','not in','&','|','and','or','+','-','*','/','**','//','%').","For bitwise XOR on boolean Series, use the python engine and rewrite as ~(a == b) logic, or apply Series operators directly outside eval.","If this surfaces from a user expression, double-check that a custom parser is not emitting unsupported tokens."],"exampleFix":"# before\nfrom pandas.core.computation.ops import BinOp, Term\nBinOp('^', lhs_term, rhs_term)  # ValueError: Invalid binary operator '^'\n\n# after\n# XOR is not in the eval grammar; compute directly:\nresult = lhs ^ rhs   # Series ^ Series","handlingStrategy":"validation","validationCode":"from pandas.core.computation.ops import _binary_ops_dict\n\ndef assert_binary_op(op: str) -> str:\n    if op not in _binary_ops_dict:\n        raise ValueError(f'{op!r} not supported; use one of {sorted(_binary_ops_dict)}')\n    return op","typeGuard":"from pandas.core.computation.ops import _binary_ops_dict\n\ndef is_supported_binary_op(op: str) -> bool:\n    return op in _binary_ops_dict\n","tryCatchPattern":"try:\n    binop = BinOp(op, lhs, rhs)\nexcept ValueError as e:\n    if 'Invalid binary operator' in str(e):\n        # fall back to direct Series operator\n        ...\n    raise","preventionTips":["Do not construct BinOp directly; use pd.eval/df.query with standard operators.","Restrict op tokens to CMP_OPS_SYMS, BOOL_OPS_SYMS, ARITH_OPS_SYMS.","For XOR and other unsupported ops, compute on Series outside eval."],"tags":["pandas","eval","operators","internal"],"analyzedSha":"71959b8cb9b2459c16e14b34f28b178ccfe14735","analyzedAt":"2026-08-07T01:30:20.476Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}