pola-rs/polars · error · ShapeError

data does not match the number of columns

Error message

data does not match the number of columns

What it means

While unpacking a `schema` argument for DataFrame construction, polars derives column names and compares their count against n_expected — the number of columns the data actually provides. A mismatch raises ShapeError (from polars.exceptions), covering sequence/list-style schemas where the number of names disagrees with the data's column count.

Source

Thrown at py-polars/src/polars/_utils/construction/dataframe.py:226

        return columns, schema_overrides

    # determine column names from schema
    if isinstance(schema, Mapping):
        column_names: list[str] = list(schema)
        schema = list(schema.items())
    else:
        column_names = []
        for i, col in enumerate(schema):
            if isinstance(col, str):
                unnamed = not col and col not in schema_overrides
                col = f"column_{i}" if unnamed else col
            else:
                col = col[0]
            column_names.append(col)

    if n_expected is not None and len(column_names) != n_expected:
        msg = "data does not match the number of columns"
        raise ShapeError(msg)

    # determine column dtypes from schema and lookup_names
    lookup: dict[str, str] | None = (
        {
            col: name
            for col, name in zip_longest(column_names, lookup_names)
            if name is not None
        }
        if lookup_names
        else None
    )

    column_dtypes: dict[str, PolarsDataType] = {}
    for col in schema:
        if isinstance(col, str):
            continue

        name, dtype = col

View on GitHub (pinned to df599052da)

Solutions

  1. Make the lengths agree — one name per data column
  2. Omit the schema and rename afterwards: `df.rename({"old": "new"})` or `df.columns = [...]`
  3. Generate names programmatically: `schema=[f"column_{i}" for i in range(n_cols)]`
  4. Catch `polars.exceptions.ShapeError` at the boundary to re-raise an app-level message with the data's actual width

Example fix

# before
pl.DataFrame([[1, 2], [3, 4]], schema=["a"])
# ShapeError: data does not match the number of columns

# after
pl.DataFrame([[1, 2], [3, 4]], schema=["a", "b"])
Defensive patterns

Strategy: validation

Validate before calling

import polars as pl

def width(rows: list[list]) -> int:
    return len(rows[0]) if rows else 0

names = ["a", "b"]
rows = [[1, 2], [3, 4]]
assert len(names) == width(rows), f"schema has {len(names)} names but data has {width(rows)} columns"
df = pl.DataFrame(rows, schema=names, orient="row")

Type guard

def schema_matches_width(schema: list[str] | None, n_cols: int) -> bool:
    """True if schema length equals the data's column count (or schema is None)."""
    return schema is None or len(schema) == n_cols

Try / catch

from polars.exceptions import ShapeError

try:
    df = pl.DataFrame(rows, schema=names)
except ShapeError as e:
    raise ValueError(f"input width changed: expected {len(names)} columns, got {len(rows[0]) if rows else 0}") from e

Prevention

When it happens

Trigger: `pl.DataFrame([[1, 2], [3, 4]], schema=["a"])` (2 data columns, 1 schema name), or `pl.DataFrame(data_with_3_columns, schema=["a", "b"])` — any positional schema whose length differs from the number of columns in the data.

Common situations: Hardcoded name lists not updated after upstream added/removed a field; ragged row data producing an unexpected column count; schemas written for one dataset reused on another with a different width.

Related errors


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