pandas-dev/pandas · error · ValueError
Invalid binary operator {op!r}, valid operators are {keys}
Error message
Invalid binary operator {op!r}, valid operators are {keys} What it means
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.
Source
Thrown at pandas/core/computation/ops.py:363
lhs : Term or Op
rhs : Term or Op
"""
def __init__(self, op: str, lhs, rhs) -> None:
super().__init__(op, (lhs, rhs))
self.lhs = lhs
self.rhs = rhs
self._disallow_scalar_only_bool_ops()
self.convert_values()
try:
self.func = _binary_ops_dict[op]
except KeyError as err:
# has to be made a list for python3
keys = list(_binary_ops_dict.keys())
raise ValueError(
f"Invalid binary operator {op!r}, valid operators are {keys}"
) from err
def __call__(self, env):
"""
Recursively evaluate an expression in Python space.
Parameters
----------
env : Scope
Returns
-------
object
The result of an evaluated expression.
"""
# recurse over the left/right nodes
left = self.lhs(env)View on GitHub (pinned to 71959b8cb9)
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.
Example fix
# before
from pandas.core.computation.ops import BinOp, Term
BinOp('^', lhs_term, rhs_term) # ValueError: Invalid binary operator '^'
# after
# XOR is not in the eval grammar; compute directly:
result = lhs ^ rhs # Series ^ Series Defensive patterns
Strategy: validation
Validate before calling
from pandas.core.computation.ops import _binary_ops_dict
def assert_binary_op(op: str) -> str:
if op not in _binary_ops_dict:
raise ValueError(f'{op!r} not supported; use one of {sorted(_binary_ops_dict)}')
return op Type guard
from pandas.core.computation.ops import _binary_ops_dict
def is_supported_binary_op(op: str) -> bool:
return op in _binary_ops_dict
Try / catch
try:
binop = BinOp(op, lhs, rhs)
except ValueError as e:
if 'Invalid binary operator' in str(e):
# fall back to direct Series operator
...
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid unary operator {op!r}, valid operators are {UNARY_OP
- keyword error in function call '{node.func.id}'
- No accumulation for {func} implemented on BaseMaskedArray
- No accumulation for {func} implemented on BaseMaskedArray
- Could not infer freq from start/end
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/ddbc81a3231d3896.
Report an issue: GitHub.