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

  1. Collect and compare data: `lf1.collect().equals(lf2.collect())`
  2. To compare plans in tests, serialize them: `lf1.serialize() == lf2.serialize()`
  3. For element-wise comparison, build an expression (`pl.col('a') == pl.col('b')`) and use `select`/`with_columns` — never bare frames
  4. 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

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


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/a2e811a605cf0708. Report an issue: GitHub.