pola-rs/polars · error · TypeError
the truth value of a Series is ambiguous Here are some…
Error message
the truth value of a Series is ambiguous Here are some things you might want to try: - instead of `if s`, use `if not s.is_empty()` - instead of `s1 and s2`, use `s1 & s2` - instead of `s1 or s2`, use `s1 | s2` - instead of `s in [y, z]`, use `s.is_in([y, z])`
What it means
Polars refuses to convert a multi-element Series to a single boolean, because the result would be ambiguous (does `if s` mean 'non-empty', 'all true', or 'any true'?). Series.__bool__ deliberately raises TypeError with guidance pointing to the intended alternatives. This mirrors pandas' classic 'truth value of a Series is ambiguous' error, which almost always indicates a Python boolean operator was used where an elementwise one was meant.
Solutions
- Replace boolean operators with elementwise ones: `s1 and s2` -> `s1 & s2`, `s1 or s2` -> `s1 | s2`, `not s` -> `~s` (wrap compound comparisons in parentheses due to precedence).
- If the intent was an emptiness check, use `if not s.is_empty():` or `if len(s) == 0:`.
- If the intent was membership, use `s.is_in([y, z])` instead of `s in [y, z]`.
- If you expected a scalar, extract it explicitly before the boolean context: `if s.item():` (fails loudly if length != 1), or use `s.any()`, `s.all()`, `s.sum()` as appropriate.
Example fix
// before
if (s > 0) and (s < 10): # TypeError: the truth value of a Series is ambiguous
...
// after
mask = (s > 0) & (s < 10)
if mask.all():
... Defensive patterns
Strategy: type-guard
Validate before calling
assert isinstance(x, pl.Series)
if not isinstance(x, bool):
# a Series in a boolean context will raise; reduce explicitly first
x = x.all() # or x.any() / x.item(), depending on intent Type guard
def is_scalar_bool(v) -> bool:
return isinstance(v, bool) # only bare bools are safe in if/and/or/not Try / catch
try:
if s and other:
...
except TypeError as e:
if 'truth value of a Series is ambiguous' in str(e):
if (s & other).all():
...
else:
raise Prevention
- Never use a Series directly in if/and/or/not; always reduce with .all(), .any(), or .item() when a scalar is intended.
- Use elementwise operators & | ~ for combining Series masks, with parentheses around each comparison.
- Replace `x in [series_list]` membership tests with series.is_in([...]).
- Check function return types: prefer .item() over a length-1 Series when a scalar is expected.
- Enable type checkers (mypy/pyright) so Series-vs-bool misuse is caught statically.
When it happens
Trigger: Using a Series in any boolean context: `if s:`, `assert s`, `s1 and s2`, `s1 or s2`, `not s`, `s in [y, z]`, or `bool(s)` — anything that invokes bool() on the Series (e.g. a function expected to return a scalar actually returning a Series, then used in `if`).
Common situations: Translating scalar if-statements from pandas/numpy code; chaining conditions with `and`/`or` instead of `&`/`|`; membership checks written as `x in [s1, s2]`; filtering results expected to be scalars but returned as one-element Series.
Related errors
- accessing ` ` from the top-level `polars` module was…
- altair>=5.4.0 is required for `.plot`
- `arctan2` expected a `str` or `Expr` got a
- `arctan2` expected a `str` or `Expr` got a
- arr.dot query vector must be one-dimensional
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/e09a5c6f1bffdf27.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/series/series.py:638
Examples
--------
>>> s = pl.Series("a", [1, 2, 3])
>>> s.shape
(3,)
"""
return (self._s.len(),)
def __bool__(self) -> NoReturn:
msg = (
"the truth value of a Series is ambiguous"
"\n\n"
"Here are some things you might want to try:\n"
"- instead of `if s`, use `if not s.is_empty()`\n"
"- instead of `s1 and s2`, use `s1 & s2`\n"
"- instead of `s1 or s2`, use `s1 | s2`\n"
"- instead of `s in [y, z]`, use `s.is_in([y, z])`\n"
)
raise TypeError(msg)
def __getstate__(self) -> bytes:
return self._s.__getstate__()
def __setstate__(self, state: bytes) -> None:
self._s = Series()._s # Initialize with a dummy
self._s.__setstate__(state)
def __str__(self) -> str_:
s_repr: str = self._s.as_str()
return s_repr.replace("Series", f"{self.__class__.__name__}", 1)
def __repr__(self) -> str_:
return self.__str__()
def __len__(self) -> int:
return self.len()
View on GitHub (pinned to fe841f959e)