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 csvView on GitHub (pinned to df599052da)
Solutions
- Fix the spelling: use 'calamine' (default), 'xlsx2csv', or 'openpyxl'
- Type the variable as Literal['calamine','xlsx2csv','openpyxl'] so mypy/pyright rejects bad values at lint time
- 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
- Annotate engine variables as Literal['calamine','xlsx2csv','openpyxl'] so mypy/pyright reject typos statically
- Validate engine strings coming from config files before use (they bypass static typing)
- After polars upgrades, grep for removed engine names (e.g. 'pyxlsb') — calamine now covers those formats
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
- '{type(self).__name__}' object has no attribute {name!r}. Di
- cannot specify both `columns` and `read_options["columns"]`
- the values of `has_header` and `read_options["has_header"]`
- cannot specify both `infer_schema_length` and `read_options[
- cannot specify both `sheet_name` ({sheet_name!r}) and `sheet
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/c2e40f7b5809540f.
Report an issue: GitHub.