pola-rs/polars · error · TypeError

cannot describe a LazyFrame that has no columns

Error message

cannot describe a LazyFrame that has no columns

What it means

LazyFrame.describe() computes summary statistics per column, which is impossible when the frame's collected schema is empty (zero columns). Polars raises a TypeError rather than returning an empty summary.

Solutions

  1. Guard with `if lf.collect_schema(): lf.describe()` before calling
  2. Ensure the pipeline retains at least one column before describing
  3. Row-empty frames with columns are fine — only zero-column schemas fail

Example fix

// before
summary = lf.describe()

// after
summary = lf.describe() if lf.collect_schema() else None
Defensive patterns

Strategy: validation

Validate before calling

schema = lf.collect_schema()
if not schema:
    raise ValueError("LazyFrame has no columns; cannot describe")

Type guard

def describable(lf: pl.LazyFrame) -> bool:
    return len(lf.collect_schema()) > 0

Try / catch

try:
    summary = lf.describe()
except TypeError as e:
    if "no columns" in str(e):
        summary = None
    else:
        raise

Prevention

When it happens

Trigger: `lf.describe()` on an empty-schema frame, e.g. `pl.LazyFrame()`, or after a select() that drops all columns.

Common situations: Describing dynamically-built frames where upstream selects removed every column; conditional column selection yielding zero columns; empty templates not yet populated.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/de28a7cb9b747063. Report an issue: GitHub.

Appendix: source

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

        │ null_count ┆ 0.0      ┆ 1.0      ┆ 0.0      ┆ 0    ┆ 0                   ┆ 0        │
        │ mean       ┆ 2.266667 ┆ 45.0     ┆ 0.666667 ┆ null ┆ 2021-07-02 16:00:00 ┆ 16:07:10 │
        │ std        ┆ 1.101514 ┆ 7.071068 ┆ null     ┆ null ┆ null                ┆ null     │
        │ min        ┆ 1.0      ┆ 40.0     ┆ 0.0      ┆ xx   ┆ 2020-01-01          ┆ 10:20:30 │
        │ 10%        ┆ 1.36     ┆ 41.0     ┆ null     ┆ null ┆ 2020-04-20          ┆ 11:13:34 │
        │ 30%        ┆ 2.08     ┆ 43.0     ┆ null     ┆ null ┆ 2020-11-26          ┆ 12:59:42 │
        │ 50%        ┆ 2.8      ┆ 45.0     ┆ null     ┆ null ┆ 2021-07-05          ┆ 14:45:50 │
        │ 70%        ┆ 2.88     ┆ 47.0     ┆ null     ┆ null ┆ 2022-02-07          ┆ 18:09:34 │
        │ 90%        ┆ 2.96     ┆ 49.0     ┆ null     ┆ null ┆ 2022-09-13          ┆ 21:33:18 │
        │ max        ┆ 3.0      ┆ 50.0     ┆ 1.0      ┆ zz   ┆ 2022-12-31          ┆ 23:15:10 │
        └────────────┴──────────┴──────────┴──────────┴──────┴─────────────────────┴──────────┘
        """  # noqa: W505
        from polars.convert import from_dict

        schema = self.collect_schema()

        if not schema:
            msg = "cannot describe a LazyFrame that has no columns"
            raise TypeError(msg)

        # create list of metrics
        metrics = ["count", "null_count", "mean", "std", "min"]
        if quantiles := parse_percentiles(percentiles):
            metrics.extend(f"{q * 100:g}%" for q in quantiles)
        metrics.append("max")

        @lru_cache
        def skip_minmax(dt: PolarsDataType) -> bool:
            return (
                dt.is_nested()
                or dt.is_extension()
                or dt in (Categorical, Enum, Null, Object, Unknown)
            )

        # determine which columns will produce std/mean/percentile/etc
        # statistics in a single pass over the frame schema
        has_numeric_result, sort_cols = set(), set()

View on GitHub (pinned to fe841f959e)