{"record":{"id":"f0adfc8a615416cd","repo":"pola-rs/polars","slug":"file-source-name-r-must-be-opened-in-binary-mode","errorCode":null,"errorMessage":"file {source.name!r} must be opened in binary mode","messagePattern":"file (.+?) must be opened in binary mode","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/io/spreadsheet/functions.py","lineNumber":889,"sourceCode":"\n    elif engine == \"calamine\":\n        fastexcel = import_optional(\"fastexcel\", min_version=\"0.7.0\")\n        reading_bytesio, reading_bytes = (\n            isinstance(source, BytesIO),\n            isinstance(source, bytes),\n        )\n        if (reading_bytesio or reading_bytes) and parse_version(\n            module_version := fastexcel.__version__\n        ) < (0, 10):\n            msg = f\"`fastexcel` >= 0.10 is required to read bytes; found {module_version})\"\n            raise ModuleUpgradeRequiredError(msg)\n\n        if reading_bytesio:\n            source = source.getvalue()  # type: ignore[union-attr]\n        elif isinstance(source, (BufferedReader, TextIOWrapper)):\n            if \"b\" not in source.mode:\n                msg = f\"file {source.name!r} must be opened in binary mode\"\n                raise OSError(msg)\n            elif (filename := source.name) and Path(filename).exists():\n                source = filename\n            else:\n                source = source.read()\n\n        parser = fastexcel.read_excel(source, **engine_options)\n        sheets = [\n            {\"index\": i + 1, \"name\": nm} for i, nm in enumerate(parser.sheet_names)\n        ]\n        return _read_spreadsheet_calamine, parser, sheets\n\n    msg = f\"unrecognized engine: {engine!r}\"\n    raise NotImplementedError(msg)\n\n\ndef _csv_buffer_to_frame(\n    csv: StringIO,\n    *,","sourceCodeStart":871,"sourceCodeEnd":907,"githubUrl":"https://github.com/pola-rs/polars/blob/fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e/py-polars/src/polars/io/spreadsheet/functions.py#L871-L907","documentation":"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.","triggerScenarios":"`pl.read_excel(open('f.xlsx'))` (default text mode) or `open('f.xlsx', 'r')` with engine='fastexcel'.","commonSituations":"Forgetting mode='rb' when opening workbooks; wrapping an Excel file in a text pipeline; code refactored from csv.read (text) to Excel reading.","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"],"exampleFix":"// before\nwith open('data.xlsx') as f:\n    pl.read_excel(f)\n// after\nwith open('data.xlsx', 'rb') as f:\n    pl.read_excel(f)","handlingStrategy":"validation","validationCode":"if hasattr(src, 'mode'):\n    assert 'b' in src.mode, 'Excel file handles must be opened in binary mode'\n\ntypeGuard: def is_binary_handle(src) -> bool:\n    return hasattr(src, 'mode') and 'b' in src.mode","typeGuard":"def is_binary_handle(src) -> bool:\n    return hasattr(src, 'mode') and 'b' in src.mode","tryCatchPattern":"try:\n    df = pl.read_excel(handle)\nexcept OSError as e:\n    if 'binary mode' in str(e):\n        df = pl.read_excel(handle.name)\n    else:\n        raise","preventionTips":["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"],"tags":["python","polars","file-handle","binary-mode","excel"],"backgroundTag":"incompatible-source-type","analyzedSha":"fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e","analyzedAt":"2026-09-18T22:14:11.667Z","contentChangedAt":"2026-09-18T22:14:11.667Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}