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() builds summary statistics per column, so it needs at least one column. If collect_schema() returns an empty schema (zero columns), polars raises TypeError rather than returning an empty table. This can only happen when the lazy plan itself selects zero columns, e.g. after select() of an empty list or reading an empty/edge-case source.

Source

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

        │ 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 df599052da)

Solutions

  1. Inspect lf.collect_schema().names() to see why the plan has no columns
  2. Guard: if len(lf.collect_schema()) == 0, skip describe or fix the pipeline upstream
  3. Fix the select()/selector logic so at least one column survives
  4. If columns are chosen dynamically, fall back to a known column list when selection is empty

Example fix

# before
stats = lf.select(cs.numeric()).describe()  # may have zero columns

# after
num = cs.numeric()
if len(lf.select(num).collect_schema()) > 0:
    stats = lf.select(num).describe()
else:
    stats = None
Defensive patterns

Strategy: validation

Validate before calling

if len(lf.collect_schema().names()) == 0:
    raise ValueError('pipeline produced a LazyFrame with no columns')
stats = lf.describe()

Type guard

def has_columns(lf) -> bool:
    return len(lf.collect_schema()) > 0

Try / catch

try:
    stats = lf.describe()
except TypeError:
    stats = None  # or fix upstream column selection

Prevention

When it happens

Trigger: lf.select([]).describe(); scanning a file whose schema resolution yields no columns; a pipeline step that drops all columns (e.g. select with a selector that matches nothing, like cs.numeric() on an all-string frame).

Common situations: Dynamic column selection with selectors that match zero columns; empty test fixtures; data files with unexpected schemas after an upstream change.

Related errors


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