pola-rs/polars · error · TypeError
the truth value of an Expr is ambiguous You probably got he
Error message
the truth value of an Expr is ambiguous
You probably got here by using a Python standard library function instead of the native expressions API.
Here are some things you might want to try:
- instead of `pl.col('a') and pl.col('b')`, use `pl.col('a') & pl.col('b')`
- instead of `pl.col('a') in [y, z]`, use `pl.col('a').is_in([y, z])`
- instead of `max(pl.col('a'), pl.col('b'))`, use `pl.max_horizontal(pl.col('a'), pl.col('b'))`
What it means
Expr defines __bool__ to raise TypeError because a lazy expression has no truth value until it is evaluated against data. Python invokes __bool__ for `if expr:`, `and`, `or`, `not`, builtin any/all, and truthiness checks on max/min results. Polars' message lists the native replacements: &, |, is_in, and horizontal aggregate functions.
Source
Thrown at py-polars/src/polars/expr/expr.py:332
else:
return "only during sphinx"
def __hash__(self) -> int:
msg = f"unhashable type: 'Expr'\n\nConsider hashing '{self}.meta'."
raise TypeError(msg)
def __bool__(self) -> NoReturn:
msg = (
"the truth value of an Expr is ambiguous"
"\n\n"
"You probably got here by using a Python standard library function instead "
"of the native expressions API.\n"
"Here are some things you might want to try:\n"
"- instead of `pl.col('a') and pl.col('b')`, use `pl.col('a') & pl.col('b')`\n"
"- instead of `pl.col('a') in [y, z]`, use `pl.col('a').is_in([y, z])`\n"
"- instead of `max(pl.col('a'), pl.col('b'))`, use `pl.max_horizontal(pl.col('a'), pl.col('b'))`\n"
)
raise TypeError(msg)
def __abs__(self) -> Expr:
return self.abs()
# operators
def __add__(self, other: IntoExpr) -> Expr:
other_pyexpr = parse_into_expression(other, str_as_lit=True)
return wrap_expr(self._pyexpr + other_pyexpr)
def __radd__(self, other: IntoExpr) -> Expr:
other_pyexpr = parse_into_expression(other, str_as_lit=True)
return wrap_expr(other_pyexpr + self._pyexpr)
def __and__(self, other: IntoExprColumn | int | bool) -> Expr:
other_pyexpr = parse_into_expression(other)
return wrap_expr(self._pyexpr.and_(other_pyexpr))
def __rand__(self, other: IntoExprColumn | int | bool) -> Expr:View on GitHub (pinned to df599052da)
Solutions
- Boolean operators: use & | ~ instead of and/or/not
- Membership: use .is_in([y, z]) instead of `in [y, z]`
- Aggregates: use pl.max_horizontal(...) / pl.min_horizontal(...) instead of builtin max()/min()
- When you genuinely need a Python branch, materialise first: value = df.select(expr).item(), then branch on value
Example fix
# before
if pl.col('a') > 5 and pl.col('b') < 3:
... # TypeError at build time
cond = max(pl.col('a'), pl.col('b'))
# after
df.filter((pl.col('a') > 5) & (pl.col('b') < 3))
cond = pl.max_horizontal(pl.col('a'), pl.col('b')) Defensive patterns
Strategy: type-guard
Validate before calling
import polars as pl
def materialise_bool(e) -> bool:
if isinstance(e, pl.Expr):
raise TypeError('cannot branch on an Expr; evaluate it first, e.g. df.select(e).item()')
return bool(e) Type guard
import polars as pl
from typing import TypeGuard
def is_polars_expr(x) -> TypeGuard[pl.Expr]:
return isinstance(x, pl.Expr)
# before any `if x:` on dynamic values
columns = [x for x in parts if not is_polars_expr(x)] Prevention
- Use & | ~ and .is_in() inside expressions; never and/or/not/in
- Use pl.max_horizontal / pl.min_horizontal instead of builtin max/min
- Materialise with df.select(expr).item() before Python control flow
When it happens
Trigger: if pl.col('a') > 5: ...; pl.col('a') and pl.col('b'); not pl.col('a').is_null(); max(pl.col('a'), pl.col('b')); assert pl.col('cnt') > 0 — all raise at expression build time.
Common situations: Copy-pasting pandas/pure-Python logic into lazy pipelines; using builtin max/min instead of pl.max_horizontal/pl.min_horizontal; debugging with if/print around expression objects.
Related errors
- unhashable type: 'Expr' Consider hashing '{self}.meta'.
- escape_regex function is unsupported for `Expr`, you may wan
- the truth value of a DataFrame is ambiguous Hint: to check
- DataTypeGroup items must be dtypes; found {qualified_type_na
- Only call is implemented not {method}
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/7ec725dc4acfd5dc.
Report an issue: GitHub.