pola-rs/polars · error · OSError
file must be opened in binary mode
Error message
file {source.name!r} must be opened in binary mode What it means
When a file-handle source is passed to `read_excel` with the fastexcel engine, it must be opened in binary mode ('b'); text-mode handles raise `OSError` because fastexcel needs raw bytes to parse the xlsx container.
Solutions
- Open the file with mode 'rb': `open(path, 'rb')`
- Or simply pass the path string/Path directly instead of a handle
- If using a text handle by mistake, read bytes from a separate binary handle
Example fix
// before
with open('data.xlsx') as f:
pl.read_excel(f)
// after
with open('data.xlsx', 'rb') as f:
pl.read_excel(f) Defensive patterns
Strategy: validation
Validate before calling
if hasattr(src, 'mode'):
assert 'b' in src.mode, 'Excel file handles must be opened in binary mode'
typeGuard: def is_binary_handle(src) -> bool:
return hasattr(src, 'mode') and 'b' in src.mode Type guard
def is_binary_handle(src) -> bool:
return hasattr(src, 'mode') and 'b' in src.mode Try / catch
try:
df = pl.read_excel(handle)
except OSError as e:
if 'binary mode' in str(e):
df = pl.read_excel(handle.name)
else:
raise Prevention
- Always open Excel files with mode='rb'
- Prefer passing path strings/Path objects over handles
- Keep binary handles for Excel and text handles for CSV; never share patterns between them
When it happens
Trigger: `pl.read_excel(open('f.xlsx'))` (default text mode) or `open('f.xlsx', 'r')` with engine='fastexcel'.
Common situations: Forgetting mode='rb' when opening workbooks; wrapping an Excel file in a text pipeline; code refactored from csv.read (text) to Excel reading.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- cannot specify both `columns` and `read_options["columns"]`
- cannot specify both `columns` and…
- cannot specify both `infer_schema_length` and…
- cannot specify both `sheet_name
- no matching sheet found when `sheet_id` is
AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18).
Data as JSON: /api/errors/f0adfc8a615416cd.
Report an issue: GitHub.
Appendix: source
Thrown at py-polars/src/polars/io/spreadsheet/functions.py:889
elif engine == "calamine":
fastexcel = import_optional("fastexcel", min_version="0.7.0")
reading_bytesio, reading_bytes = (
isinstance(source, BytesIO),
isinstance(source, bytes),
)
if (reading_bytesio or reading_bytes) and parse_version(
module_version := fastexcel.__version__
) < (0, 10):
msg = f"`fastexcel` >= 0.10 is required to read bytes; found {module_version})"
raise ModuleUpgradeRequiredError(msg)
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,
*,View on GitHub (pinned to fe841f959e)