pola-rs/polars · error · NotImplementedError

unrecognized engine: {engine!r}

Error message

unrecognized engine: {engine!r}

What it means

Raised by _initialise_spreadsheet_parser as a NotImplementedError when the engine string matches none of the supported values 'calamine', 'xlsx2csv', 'openpyxl'. read_excel's default is 'calamine' and read_ods always forces calamine internally, so in practice this means a misspelled or obsolete engine string was passed to read_excel at runtime (the parameter is a Literal type, so type checkers catch it statically).

Source

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

        if reading_bytesio:
            source = source.getvalue()  # type: ignore[union-attr]
        elif isinstance(source, (BufferedReader, TextIOWrapper)):
            if "b" not in source.mode:
                msg = f"file {source.name!r} must be opened in binary mode"
                raise OSError(msg)
            elif (filename := source.name) and Path(filename).exists():
                source = filename
            else:
                source = source.read()

        parser = fastexcel.read_excel(source, **engine_options)
        sheets = [
            {"index": i + 1, "name": nm} for i, nm in enumerate(parser.sheet_names)
        ]
        return _read_spreadsheet_calamine, parser, sheets

    msg = f"unrecognized engine: {engine!r}"
    raise NotImplementedError(msg)


def _csv_buffer_to_frame(
    csv: StringIO,
    *,
    separator: str,
    read_options: dict[str, Any],
    schema_overrides: SchemaDict | None,
    drop_empty_rows: bool,
    drop_empty_cols: bool,
    raise_if_empty: bool,
) -> pl.DataFrame:
    """Translate StringIO buffer containing delimited data as a DataFrame."""
    # handle (completely) empty sheet data
    if csv.tell() == 0:
        return _empty_frame(raise_if_empty)

    # otherwise rewind the buffer and parse as csv

View on GitHub (pinned to df599052da)

Solutions

  1. Fix the spelling: use 'calamine' (default), 'xlsx2csv', or 'openpyxl'
  2. Type the variable as Literal['calamine','xlsx2csv','openpyxl'] so mypy/pyright rejects bad values at lint time
  3. If you depended on a removed engine (e.g. pyxlsb), switch to 'calamine', which handles xlsb via fastexcel

Example fix

# before
pl.read_excel(src, engine='pyxlsb')  # removed/unsupported -> NotImplementedError

# after
pl.read_excel(src, engine='calamine')  # fastexcel reads xlsb/xls/xlsx/ods
Defensive patterns

Strategy: type-guard

Validate before calling

SUPPORTED_ENGINES = {'calamine', 'xlsx2csv', 'openpyxl'}
if engine not in SUPPORTED_ENGINES:
    raise ValueError(f'engine must be one of {sorted(SUPPORTED_ENGINES)}, got {engine!r}')
df = pl.read_excel(src, engine=engine)

Type guard

from typing import Literal, TypeGuard

ExcelEngine = Literal['calamine', 'xlsx2csv', 'openpyxl']

def is_excel_engine(value: str) -> TypeGuard[ExcelEngine]:
    return value in {'calamine', 'xlsx2csv', 'openpyxl'}

assert is_excel_engine(engine), f'unsupported engine: {engine!r}'

Prevention

When it happens

Trigger: pl.read_excel(src, engine='calamel') (typo); engine='pyxlsb' or 'xlrd' — names of engines removed or never supported by this polars version; engine values read from config files that bypass static typing.

Common situations: Code written against an older polars whose engine set differed, run after an upgrade; engine selected dynamically from a settings file; autocomplete-induced typos.

Related errors


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