pola-rs/polars · error · TypeError
expected a selector; found
Error message
expected a selector; found {selector!r} instead. What it means
polars.selectors.expand_selector() requires its `selector` argument to be a genuine ColumnSelector (or, with strict=False, an expression that resolves purely to a column selection). When passed anything else — a plain string, column name list, Expr with arithmetic, etc. — it raises this TypeError instead of attempting an invalid selection.
Solutions
- Wrap the column name in a selector: use cs.by_name('colname') instead of the bare string.
- If the argument may be a plain name, convert conditionally: selector = cs.by_name(x) if isinstance(x, str) else x.
- For expressions involving exclude or aliasing, pass strict=False only if the expression is still a pure column selection.
- Verify with polars.selectors.is_selector(obj) before calling expand_selector.
Example fix
// before
cols = cs.expand_selector(df, "colx")
// after
cols = cs.expand_selector(df, cs.by_name("colx")) Defensive patterns
Strategy: type-guard
Validate before calling
from polars.selectors import is_selector
if not is_selector(sel):
sel = cs.by_name(sel) if isinstance(sel, str) else None
if sel is None:
raise ValueError(f"not a selector: {sel!r}") Type guard
def is_valid_selector(obj) -> bool:
from polars.selectors import is_selector
return is_selector(obj) or (hasattr(obj, 'meta') and obj.meta.is_column_selection(allow_aliasing=False)) Try / catch
try:
cols = cs.expand_selector(df, sel)
except TypeError as e:
if "expected a selector" in str(e):
cols = cs.expand_selector(df, cs.by_name(sel))
else:
raise Prevention
- Always wrap raw column names with cs.by_name before expand_selector.
- Use polars.selectors.is_selector() as a precondition assert in helper functions.
- Remember strict=False only relaxes to pure-column-selection Exprs, not strings.
When it happens
Trigger: Calling cs.expand_selector(df, 'colname') or cs.expand_selector(df, pl.col('a') + 1) — i.e. passing a str, Expr, or other non-selector object. With strict=False, passing an Expr that aliases, renames, or computes values (meta.is_column_selection is False).
Common situations: Confusing expand_selector with select(); refactoring code where a string column name was previously accepted; dynamically built expressions that accidentally lose selector status; passing a cs.exclude(...) result into expand_selector without strict=False.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- cannot parse input into Polars selector
- cannot turn into selector
- cannot turn into selector
- expected one or more `str`, `DataType` or selector; found
- invalid dtype
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/6dbf322aa3533374.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/selectors.py:186
Allow for non-strict selection expressions (such as those
including use of an `.exclude()` constraint) to be expanded:
>>> cs.expand_selector(schema, cs.numeric().exclude("id"), strict=False)
('count', 'value')
"""
if isinstance(target, Mapping):
from polars.dataframe import DataFrame
target = DataFrame(schema=target)
if not (
is_selector(selector)
if strict
else selector.meta.is_column_selection(allow_aliasing=False)
):
msg = f"expected a selector; found {selector!r} instead."
raise TypeError(msg)
return tuple(target.select(selector).collect_schema())
# TODO: Don't use this as it collects a schema (can be very expensive for LazyFrame).
# This should move to IR conversion / Rust.
def _expand_selectors(frame: DataFrame | LazyFrame, *items: Any) -> builtins.list[str]:
"""
Internal function that expands any selectors to column names in the given input.
Non-selector values are left as-is.
Examples
--------
>>> from polars.selectors import _expand_selectors
>>> import polars.selectors as cs
>>> df = pl.DataFrame(
... {View on GitHub (pinned to fe841f959e)