pola-rs/polars · error · ModuleUpgradeRequiredError

a more recent version of `fastexcel` is required for 'schema

Error message

a more recent version of `fastexcel` is required for 'schema_sample_rows' (>= 0.9; found {original_version})

What it means

Raised as ModuleUpgradeRequiredError in _read_spreadsheet_calamine when read_options contains 'schema_sample_rows' and the installed fastexcel is older than 0.9.0. Crucially, for the calamine engine _get_read_options ALWAYS injects read_options['schema_sample_rows'] = infer_schema_length, so with fastexcel 0.7.x/0.8.x (which pass the 0.7.0 import floor) essentially EVERY read_excel/read_ods call with engine='calamine' hits this — read_ods is affected too because it hardcodes calamine.

Source

Thrown at py-polars/src/polars/io/spreadsheet/functions.py:1048

    parser: Any,
    *,
    sheet_name: str | None,
    read_options: dict[str, Any],
    schema_overrides: SchemaDict | None,
    columns: Sequence[int] | Sequence[str] | None,
    table_name: str | None = None,
    drop_empty_rows: bool,
    drop_empty_cols: bool,
    raise_if_empty: bool,
) -> pl.DataFrame:
    # if we have 'schema_overrides' and a more recent version of `fastexcel`
    # we can pass translated dtypes to the engine to refine the initial parse
    fastexcel = import_optional("fastexcel")
    fastexcel_version = parse_version(original_version := fastexcel.__version__)

    if fastexcel_version < (0, 9) and "schema_sample_rows" in read_options:
        msg = f"a more recent version of `fastexcel` is required for 'schema_sample_rows' (>= 0.9; found {original_version})"
        raise ModuleUpgradeRequiredError(msg)
    if fastexcel_version < (0, 10, 2) and "use_columns" in read_options:
        msg = f"a more recent version of `fastexcel` is required for 'use_columns' (>= 0.10.2; found {original_version})"
        raise ModuleUpgradeRequiredError(msg)
    if table_name and fastexcel_version < (0, 12):
        msg = f"a more recent version of `fastexcel` is required for 'table_name' (>= 0.12.0; found {original_version})"
        raise ValueError(msg)

    if columns:
        if not isinstance(columns, list):
            columns = list(columns)  # type: ignore[assignment]
        read_options["use_columns"] = columns

    schema_overrides = schema_overrides or {}
    if read_options.get("schema_sample_rows") == 0:
        # ref: https://github.com/ToucanToco/fastexcel/issues/236
        del read_options["schema_sample_rows"]
        read_options["dtypes"] = (
            "string"

View on GitHub (pinned to df599052da)

Solutions

  1. Upgrade fastexcel to at least 0.9 (recommended: latest, which also unlocks use_columns and table_name)
  2. If you cannot upgrade, use engine='xlsx2csv' or 'openpyxl' for .xlsx inputs
  3. For ODS inputs there is no alternative engine — upgrading fastexcel is the only fix

Example fix

# before: fastexcel 0.7.x pinned -> every calamine read raises
# requirements.txt: fastexcel==0.7.6

# after
pip install -U 'fastexcel>=0.12'
# requirements.txt: fastexcel>=0.12
Defensive patterns

Strategy: validation

Validate before calling

def fastexcel_version() -> tuple[int, ...]:
    import fastexcel
    return tuple(int(p) for p in fastexcel.__version__.split('.')[:3])

ver = fastexcel_version()
if ver < (0, 9):
    # schema_sample_rows is ALWAYS injected for calamine, so downgrade expectations
    df = pl.read_excel(src, engine='openpyxl')  # or 'xlsx2csv' for .xlsx
else:
    df = pl.read_excel(src)  # calamine default

Try / catch

from polars.exceptions import ModuleUpgradeRequiredError
try:
    df = pl.read_excel(src)  # engine='calamine' default; read_ods too
except ModuleUpgradeRequiredError as e:
    if "'schema_sample_rows'" in str(e):
        raise RuntimeError('fastexcel>=0.9 required: pip install -U fastexcel') from e
    raise

Prevention

When it happens

Trigger: Any pl.read_excel(src) or pl.read_ods(src) with fastexcel 0.7.x or 0.8.x installed; explicitly passing infer_schema_length or read_options={'schema_sample_rows': n} makes the trigger obvious but is not required.

Common situations: A stale fastexcel pin in requirements/lockfile while polars was upgraded (or vice versa); shared Docker images where the floor version 0.7.0 was pinned deliberately long ago; read_ods users, since there is no alternate ODS engine.

Related errors


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