pola-rs/polars · error · TypeError
unsupported operand type(s) for op: ('Selector' + 'Selector'
Error message
unsupported operand type(s) for op: ('Selector' + 'Selector') What it means
Between selectors, `+` is arithmetic addition of the selected columns' values, not set union. Selector.__radd__ (reached when Python falls back to reflected addition, e.g. a Selector subclass on the left deferring) explicitly raises TypeError when the other operand is also a Selector, rather than silently guessing between union and addition.
Source
Thrown at py-polars/src/polars/selectors.py:463
def _by_name(
cls, names: builtins.list[str], *, strict: bool, expand_patterns: bool
) -> Selector:
return cls._from_pyselector(PySelector.by_name(names, strict, expand_patterns))
def __invert__(cls) -> Selector:
"""Invert the selector."""
return all() - cls
def __add__(self, other: Any) -> Expr:
if is_selector(other):
return self.as_expr().__add__(other.as_expr())
else:
return self.as_expr().__add__(other)
def __radd__(self, other: Any) -> Expr:
if is_selector(other):
msg = "unsupported operand type(s) for op: ('Selector' + 'Selector')"
raise TypeError(msg)
else:
return self.as_expr().__radd__(other)
@overload
def __and__(self, other: Selector) -> Selector: ...
@overload
def __and__(self, other: Any) -> Expr: ...
def __and__(self, other: Any) -> Selector | Expr:
if is_column(other): # @2.0: remove
colname = other.meta.output_name()
other = by_name(colname)
if is_selector(other):
return Selector._from_pyselector(
PySelector.intersect(self._pyselector, other._pyselector)
)
else:View on GitHub (pinned to df599052da)
Solutions
- For set union use the or-operator: cs.numeric() | cs.by_name('id')
- If arithmetic addition of the selected columns is truly intended, go through expressions after selection instead of relying on reflected selector arithmetic
- Review any code building selectors with operator(+ ) and switch to | or &
Example fix
# before sel = cs.first() + cs.last() # TypeError on reflected path; ambiguous anyway # after sel = cs.first() | cs.last() # union
Defensive patterns
Strategy: type-guard
Validate before calling
from polars.selectors import is_selector
if is_selector(a) and is_selector(b):
combined = a | b # union, never '+'
else:
combined = a + b Type guard
from polars.selectors import is_selector
def safe_union(a, b):
if is_selector(a) and is_selector(b):
return a | b
raise TypeError('expected two selectors') Prevention
- Mental model: selectors are column SETS - |, &, - are set ops; +/-/* are value arithmetic
- Lint for '+' between cs.* expressions in review
When it happens
Trigger: Writing cs.a() + cs.b() intending column union; reflected addition paths where the left selector's __add__ defers; subclassed selectors combined with +.
Common situations: Users arriving from other libraries where + concatenates selections; code generators emitting `sel1 + sel2` for column sets.
Related errors
- unsupported operand type(s) for op: ('Expr' - 'Selector')
- expected a selector; found {selector!r} instead.
- expected one or more `str`, `DataType` or selector; found {i
- cannot parse input {input_type} into Polars selector{input_d
- `new` argument is required if `old` argument is not a Mappin
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/b51975f285c4e105.
Report an issue: GitHub.