pola-rs/polars · error · TypeError
"{operator!r}" comparison not supported for LazyFrame object
Error message
"{operator!r}" comparison not supported for LazyFrame objects What it means
`LazyFrame` disables all comparison operators: `__eq__`, `__ne__`, `__gt__`, `__lt__`, `__ge__`, `__le__` route through `_comparison_error` (frame.py:667) and raise TypeError. A LazyFrame is a query plan, not data, so element-wise or frame-wise comparison is meaningless until execution — and allowing `==` would break hashing/identity semantics. Note `==` does NOT silently return False; it raises.
Source
Thrown at py-polars/src/polars/lazyframe/frame.py:667
"""
issue_warning(
"determining the width of a LazyFrame requires resolving its schema,"
" which is a potentially expensive operation. Use `LazyFrame.collect_schema().len()`"
" to get the width without this warning.",
category=PerformanceWarning,
)
return self.collect_schema().len()
def __bool__(self) -> NoReturn:
msg = (
"the truth value of a LazyFrame is ambiguous"
"\n\nLazyFrames cannot be used in boolean context with and/or/not operators."
)
raise TypeError(msg)
def _comparison_error(self, operator: str) -> NoReturn:
msg = f'"{operator!r}" comparison not supported for LazyFrame objects'
raise TypeError(msg)
def __eq__(self, other: object) -> NoReturn:
self._comparison_error("==")
def __ne__(self, other: object) -> NoReturn:
self._comparison_error("!=")
def __gt__(self, other: Any) -> NoReturn:
self._comparison_error(">")
def __lt__(self, other: Any) -> NoReturn:
self._comparison_error("<")
def __ge__(self, other: Any) -> NoReturn:
self._comparison_error(">=")
def __le__(self, other: Any) -> NoReturn:
self._comparison_error("<=")View on GitHub (pinned to df599052da)
Solutions
- Collect and compare data: `lf1.collect().equals(lf2.collect())`
- To compare plans in tests, serialize them: `lf1.serialize() == lf2.serialize()`
- For element-wise comparison, build an expression (`pl.col('a') == pl.col('b')`) and use `select`/`with_columns` — never bare frames
- Remove LazyFrames from dict/set usage; use explicit identity (`is`) or collected results
Example fix
# before
if lf1 == lf2: # TypeError: '==' comparison not supported
...
# after
if lf1.collect().equals(lf2.collect()):
... Defensive patterns
Strategy: type-guard
Validate before calling
import polars as pl
def frames_equal(a: pl.LazyFrame, b: pl.LazyFrame) -> bool:
'Data equality; executes both queries.'
return a.collect().equals(b.collect())
def plans_equal(a: pl.LazyFrame, b: pl.LazyFrame) -> bool:
'Plan equality without executing.'
return a.serialize(format='json') == b.serialize(format='json')
if frames_equal(lf1, lf2): # instead of: if lf1 == lf2:
... Type guard
from typing import TypeGuard
import polars as pl
def is_lazy_frame(x: object) -> TypeGuard[pl.LazyFrame]:
return isinstance(x, pl.LazyFrame)
# narrow before comparison helpers that assume data (e.g. pandas frames):
if is_lazy_frame(other):
equal = lf.collect().equals(other.collect()) Try / catch
try:
same = lf1 == lf2
except TypeError as e:
if 'comparison not supported for LazyFrame' in str(e):
same = lf1.collect().equals(lf2.collect())
else:
raise Prevention
- Use DataFrame.equals on collected results for data equality
- Use serialized plans (lf.serialize()) for golden-file tests instead of ==
- Never put LazyFrames in sets or use them as dict keys; compare explicit keys instead
- For element-wise logic, write column expressions (pl.col('a') == pl.col('b')) inside select/with_columns
When it happens
Trigger: `lf1 == lf2`, `df_col == lf` mixing, sorting/`max()` helpers that apply `>` to operands, or `lf in [other_lf]`-style membership that uses `==`; also `lf >= something` in validation code copied from eager DataFrame logic.
Common situations: Pandas/polars-eager habit `df1 == df2` applied to lazy frames; writing generic assertion helpers that compare two query results; using LazyFrames as dict keys or in sets (hashing invokes `==` on collision); diffing golden plans in tests via `==`.
Related errors
- the truth value of a LazyFrame is ambiguous LazyFrames cann
- LazyFrame is not subscriptable (aside from slicing) Use `se
- invalid predicate for `filter`: {err}
- datetime time zone {other.tzinfo!r} does not match Series ti
- cannot select columns using key of type {qualified_type_name
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/a2e811a605cf0708.
Report an issue: GitHub.