pola-rs/polars · error · TypeError

the truth value of a LazyFrame is ambiguous LazyFrames cann

Error message

the truth value of a LazyFrame is ambiguous

LazyFrames cannot be used in boolean context with and/or/not operators.

What it means

`LazyFrame.__bool__` (frame.py:663) is deliberately disabled: a LazyFrame represents an unexecuted query, so its truth value (empty? any rows? any columns?) is undefined and computing it would silently trigger an expensive `collect`. Any boolean-context use — `if lf:`, `not lf`, `lf and x`, `bool(lf)`, `assert lf` — raises TypeError with guidance pointing away from and/or/not operators.

Source

Thrown at py-polars/src/polars/lazyframe/frame.py:663

        ...     }
        ... )
        >>> lf.width  # doctest: +SKIP
        2
        """
        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:

View on GitHub (pinned to df599052da)

Solutions

  1. Execute and check rows: `if lf.collect().height > 0:` or `if not lf.collect().is_empty():`
  2. To check the query produces columns, use `len(lf.collect_schema()) > 0` (schema resolution only, no full scan)
  3. For None-or-frame checks use `is None` explicitly, never bare truthiness
  4. Avoid `assert lf` in tests; assert on collected results or plans instead

Example fix

# before
if not lf:
    raise ValueError('empty')  # TypeError: truth value ambiguous

# after
if lf.collect().is_empty():
    raise ValueError('empty')
Defensive patterns

Strategy: type-guard

Validate before calling

import polars as pl

def nonempty(lf: pl.LazyFrame) -> bool:
    'Explicit emptiness check that runs the query.'
    return lf.collect().height > 0

def has_columns(lf: pl.LazyFrame) -> bool:
    'Cheap check that only resolves the schema.'
    return len(lf.collect_schema()) > 0

if nonempty(lf):  # instead of: if lf:
    ...

Type guard

from typing import TypeGuard
import polars as pl

def is_lazy_frame(x: object) -> TypeGuard[pl.LazyFrame]:
    return isinstance(x, pl.LazyFrame)

# use before any boolean context on mixed values:
if is_lazy_frame(obj):
    check = obj.collect().height > 0
else:
    check = bool(obj)

Try / catch

try:
    ok = bool(lf)
except TypeError as e:
    if 'truth value of a LazyFrame is ambiguous' in str(e):
        ok = lf.collect().height > 0
    else:
        raise

Prevention

When it happens

Trigger: `if not lf: ...`, `lf1 or lf2`, `assert lf` on any `LazyFrame`; also `bool(lf)` or passing a LazyFrame where Python implicitly coerces truthiness (e.g. `any([lf])`, ternaries).

Common situations: Pandas habits (`if df.empty():`, truthiness checks) carried over to lazy APIs; guard clauses like `if lf is None or lf:`; template/ORM code that truth-tests arbitrary objects; refactoring eager code to lazy without adjusting emptiness checks.

Related errors


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