pandas-dev/pandas · error · ValueError
Invalid unary operator
Error message
Invalid unary operator {op!r}, valid operators are {UNARY_OPS_SYMS} What it means
Raised in UnaryOp.__init__ when the operator string is not in _unary_ops_dict, whose keys are '+', '-', '~', 'not' (UNARY_OPS_SYMS). The valid set is printed in the message. Like the binary counterpart, this is a defensive guard: the parser only emits those four unary forms, so hitting it implies an internally constructed UnaryOp or an unsupported token such as unary '*'.
Solutions
- Restrict unary usage to '+', '-', '~', 'not' inside eval/query expressions.
- For unsupported unary forms (e.g. logical not on non-bool), rewrite using bitwise/comparison operators: df.query('~(A > 0)') instead of df.query('not (A > 0)') if 'not' is problematic.
- If extending the engine, register the operator in _unary_ops_funcs/_unary_ops_dict before constructing UnaryOp.
Example fix
// before
from pandas.core.computation.ops import UnaryOp
UnaryOp("!", operand)
// after
UnaryOp("~", operand) Defensive patterns
Strategy: validation
Validate before calling
from pandas.core.computation.ops import _unary_ops_dict
def is_supported_unary_op(op: str) -> bool:
return op in _unary_ops_dict
assert is_supported_unary_op(op_token) Type guard
from typing import Literal
SupportedUnaryOp = Literal['+', '-', '~', 'not']
def is_supported(op: str) -> bool:
return op in {'+', '-', '~', 'not'} Try / catch
try:
UnaryOp(op, operand)
except ValueError as e:
if 'Invalid unary operator' in str(e):
UnaryOp('~', operand) # fallback to invert
else:
raise Prevention
- Only emit '+', '-', '~', 'not' as unary tokens in generated expressions.
- Register custom unary operators in _unary_ops_dict before constructing UnaryOp.
- Unit-test every operator token against _unary_ops_dict.
When it happens
Trigger: Directly constructing UnaryOp(op, operand) with an operator outside ('+', '-', '~', 'not'). Custom code paths that feed an unrecognized unary token into the eval AST visitor.
Common situations: Forks/extensions trying to add new unary operators. A parser regression that produces an unexpected unary node. Misuse of internal API by downstream libraries building Op trees by hand.
Related errors
- Invalid binary operator
- Invalid function call
- keyword error in function call
- bad operand type for unary +
- can only assign a single expression
AI-assisted analysis of pandas-dev/pandas@3b7651241d (2026-08-11).
Data as JSON: /api/errors/d9e047b201fa28b2.
Report an issue: GitHub.
Appendix: source
Thrown at pandas/core/computation/ops.py:519
op : str
The token used to represent the operator.
operand : Term or Op
The Term or Op operand to the operator.
Raises
------
ValueError
* If no function associated with the passed operator token is found.
"""
def __init__(self, op: Literal["+", "-", "~", "not"], operand) -> None:
super().__init__(op, (operand,))
self.operand = operand
try:
self.func = _unary_ops_dict[op]
except KeyError as err:
raise ValueError(
f"Invalid unary operator {op!r}, valid operators are {UNARY_OPS_SYMS}"
) from err
def __call__(self, env) -> MathCall:
operand = self.operand(env)
# error: Cannot call function of unknown type
return self.func(operand) # type: ignore[operator]
def __repr__(self) -> str:
return pprint_thing(f"{self.op}({self.operand})")
@property
def return_type(self) -> np.dtype:
operand = self.operand
if operand.return_type == np.dtype("bool"):
return np.dtype("bool")
if isinstance(operand, Op) and (
operand.op in _cmp_ops_dict or operand.op in _bool_ops_dictView on GitHub (pinned to 3b7651241d)