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

  1. 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','+','-','*','/','**','//','%').
  2. For bitwise XOR on boolean Series, use the python engine and rewrite as ~(a == b) logic, or apply Series operators directly outside eval.
  3. 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

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


AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07). Data as JSON: /api/errors/ddbc81a3231d3896. Report an issue: GitHub.