pandas-dev/pandas · error · ValueError
Invalid binary operator
Error message
Invalid binary operator {op!r}, valid operators are {keys} What it means
Raised in BinOp.__init__ when the operator string is absent from _binary_ops_dict, which aggregates comparison (>, <, >=, <=, ==, !=, in, not in), boolean (&, |, and, or), and arithmetic (+, -, *, /, **, //, %) operators. The valid operator list is included in the message. This is a defensive guard; the standard parser/tokenizer only ever emits operators already in the dict, so reaching this branch usually means an internally constructed BinOp or an unsupported operator such as '@' (matmul).
Solutions
- Use only the supported operator set: comparison (>, <, >=, <=, ==, !=, in, not in), boolean (&, |, and, or), arithmetic (+, -, *, /, **, //, %).
- For bitwise XOR/shifts, perform the operation outside eval: df['A'] ^ df['B'].
- For matmul, use DataFrame.dot() or the @ operator in plain Python, not in a query string.
- If extending the engine, register your operator in _cmp_ops_dict/_bool_ops_dict/_arith_ops_dict before constructing BinOp.
Example fix
// before
from pandas.core.computation.ops import BinOp
BinOp("^", lhs, rhs)
df.query("A @ B > 1")
// after
# use vectorized op outside eval
(df['A'] ^ df['B'])
df.dot(other) Defensive patterns
Strategy: validation
Validate before calling
from pandas.core.computation.ops import _binary_ops_dict
def is_supported_binary_op(op: str) -> bool:
return op in _binary_ops_dict
assert is_supported_binary_op(op_token), f'unsupported binary operator: {op_token}' Type guard
from pandas.core.computation.ops import _binary_ops_dict
from typing import Literal
SupportedBinOp = Literal['>', '<', '>=', '<=', '==', '!=', 'in', 'not in', '&', '|', 'and', 'or', '+', '-', '*', '/', '**', '//', '%']
def is_supported(op: str) -> bool:
return op in _binary_ops_dict Try / catch
try:
BinOp(op, lhs, rhs)
except ValueError as e:
if 'Invalid binary operator' in str(e):
# fall back to python-level op
result = lhs.value ^ rhs.value
else:
raise Prevention
- Restrict generated operators to the supported set.
- If extending the engine, register custom ops in _binary_ops_dict first.
- Add a unit test that asserts every operator token you emit is in _binary_ops_dict.
When it happens
Trigger: Constructing BinOp(op, lhs, rhs) directly with an operator string outside the supported set (e.g. '@', '^', '<<'). A custom subclass or monkeypatch that injects a non-standard operator token. A future/version-change parser bug that produces an unrecognized token.
Common situations: Third-party code extending the eval engine by building BinOp instances with bitwise operators not in the dict (^, <<, >>). Attempting to use the matrix-multip operator '@' inside a query string. Forks of pandas that add operators without updating _binary_ops_dict.
Related errors
- Invalid unary operator
- Invalid function call
- keyword error in function call
- can only assign a single expression
- Cannot assign expression output to target
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/ddbc81a3231d3896.
Report an issue: GitHub.
Appendix: 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 3b7651241d)