pandas-dev/pandas · error · TypeError
boolean value of an expression is ambiguous
Error message
boolean value of an expression is ambiguous
What it means
Raised by Expression.__bool__ (pandas/core/col.py:357). `pd.col(name)` returns a deferred Expression representing a not-yet-bound column; its truth value is undefined because the column does not exist until evaluated against a DataFrame. Python calls __bool__ whenever an object is used in `if`, `and`, `or`, `not`, or ternary contexts, so this guard prevents ambiguous boolean coercion.
Source
Thrown at pandas/core/col.py:357
evaluated = []
for condition, replacement in caselist:
if isinstance(condition, Expression):
condition = condition._eval_expression(df)
if isinstance(replacement, Expression):
replacement = replacement._eval_expression(df)
evaluated.append((condition, replacement))
return ser.case_when(evaluated)
# Keep repr compact; caselist may be large.
repr_str = f"{self!r}.case_when(...)"
return Expression(func, repr_str)
def __repr__(self) -> str:
return self._repr_str or "Expr(...)"
# Unsupported ops
def __bool__(self) -> NoReturn:
raise TypeError("boolean value of an expression is ambiguous")
def __iter__(self) -> NoReturn:
raise TypeError("Expression objects are not iterable")
def __copy__(self) -> NoReturn:
raise TypeError("Expression objects are not copiable")
def __deepcopy__(self, memo: dict[int, Any] | None) -> NoReturn:
raise TypeError("Expression objects are not copiable")
@set_module("pandas")
def col(col_name: Hashable) -> Expression:
"""
Generate deferred object representing a column of a DataFrame.
Any place which accepts ``lambda df: df[col_name]``, such as
:meth:`DataFrame.assign` or :meth:`DataFrame.loc`, can also acceptView on GitHub (pinned to 71959b8cb9)
Solutions
- Use the Expression only inside a context that evaluates it against a DataFrame: `df.assign(flag=pd.col('x') > 5)` or `df.loc[pd.col('x') > 5]`.
- If you need a scalar boolean, first bind the expression to a frame and reduce: `bool((df['x'] > 5).any())`.
- Rewrite `if expr:` logic to operate on the resolved Series after evaluation.
Example fix
# before
expr = pd.col('speed') > 100
if expr:
...
# after
df = df.assign(fast=pd.col('speed') > 100) Defensive patterns
Strategy: type-guard
Validate before calling
from pandas.core.col import Expression
def assert_evaluable(expr):
if isinstance(expr, Expression):
raise TypeError("Expression cannot be used in a boolean context; evaluate against a DataFrame first") Type guard
from pandas.core.col import Expression
def is_expression(obj) -> bool:
return isinstance(obj, Expression) Try / catch
from pandas.core.col import Expression
try:
result = bool(obj)
except TypeError as e:
if 'ambiguous' in str(e) and isinstance(obj, Expression):
# evaluate against a frame and reduce instead
result = bool(obj._eval_expression(df).any())
else:
raise Prevention
- Never use pd.col expressions in if/and/or/not; only in assign/loc/query.
- Treat Expression as a deferred spec, not a concrete value.
- Reduce to a scalar bool only after binding: bool((df[col] > n).any()).
When it happens
Trigger: Writing `if pd.col('x') > 5:` (the comparison returns an Expression, not a bool), `pd.col('x') and pd.col('y')`, or `bool(pd.col('x'))`. Also `~pd.col('x')` inside an `if`, or passing an Expression to a function that does `if value:`.
Common situations: Treating a deferred Expression like a concrete value. Using `pd.col` inside conditional logic instead of inside assign/loc/query which evaluate the expression against a DataFrame.
Related errors
- Expression objects are not iterable
- Expression objects are not copiable
- Expected Hashable, got: {type(col_name)}
- Column '{col_name}' not found in given DataFrame. Hint: did
- Cannot multiply StringArray by bools. Explicitly cast to int
AI-assisted analysis of pandas-dev/pandas@71959b8cb9 (2026-08-07).
Data as JSON: /api/errors/c2f06d9fe05a5196.
Report an issue: GitHub.