{"record":{"id":"985cee5676f35e53","repo":"pola-rs/polars","slug":"no-matching-sheet-found-when-sheet-id-is-idx","errorCode":null,"errorMessage":"no matching sheet found when `sheet_id` is {idx}","messagePattern":"no matching sheet found when `sheet_id` is (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/io/spreadsheet/functions.py","lineNumber":824,"sourceCode":"            (sheet_name,) if isinstance(sheet_name, str) else sheet_name or ()\n        ):\n            known_sheet_names = {ws[\"name\"] for ws in worksheets}\n            for name in names:\n                if name not in known_sheet_names:\n                    msg = f\"no matching sheet found when `sheet_name` is {name!r}\"\n                    raise ValueError(msg)\n                sheet_names.append(name)\n        else:\n            ids = (sheet_id,) if isinstance(sheet_id, int) else sheet_id or ()\n            sheet_names_by_idx = {\n                idx: ws[\"name\"]\n                for idx, ws in enumerate(worksheets, start=1)\n                if (sheet_id == 0 or ws[\"index\"] in ids or ws[\"name\"] in names)\n            }\n            for idx in ids:\n                if (name := sheet_names_by_idx.get(idx)) is None:\n                    msg = f\"no matching sheet found when `sheet_id` is {idx}\"\n                    raise ValueError(msg)\n                sheet_names.append(name)\n\n    return sheet_names, return_multiple_sheets  # type: ignore[return-value]\n\n\ndef _initialise_spreadsheet_parser(\n    engine: str | None,\n    source: str | IO[bytes] | bytes,\n    engine_options: dict[str, Any],\n) -> tuple[Callable[..., pl.DataFrame], Any, list[dict[str, Any]]]:\n    \"\"\"Instantiate the indicated spreadsheet parser and establish related properties.\"\"\"\n    if isinstance(source, str) and not Path(source).exists():\n        raise FileNotFoundError(source)\n\n    if engine == \"xlsx2csv\":  # default\n        xlsx2csv = import_optional(\"xlsx2csv\")\n\n        # establish sensible defaults for unset options","sourceCodeStart":806,"sourceCodeEnd":842,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/io/spreadsheet/functions.py#L806-L842","documentation":"Raised by pl.read_excel / pl.read_ods in _get_sheet_names (a ValueError) when a requested sheet_id has no matching worksheet. Ids are 1-based (enumerate over worksheets starting at 1); sheet_id=0 is special and means 'all sheets', so it never triggers this error. For a sequence of ids each one must resolve, and the first missing id raises.","triggerScenarios":"sheet_id=5 on a 3-sheet workbook; sheet_id=[1,4] where only 3 sheets exist; iterating range(0, n) which sends 0 (all-sheets) then out-of-range ids; ids computed after hidden-sheet exclusion shrank the worksheet list.","commonSituations":"Assuming 0-based indexing (the classic off-by-one: sheet_id=0 quietly reads ALL sheets, sheet_id=n then fails); loops written against a workbook layout that changed; multi-sheet workbooks where some tabs were deleted upstream.","solutions":["Use 1-based ids and verify against the sheet count before calling","If you need everything, use sheet_id=0 once and index the returned {sheet_name: DataFrame} dict","Handle dynamic layouts by reading sheet names first (openpyxl sheetnames) instead of guessing ids"],"exampleFix":"# before (0-based assumption; id 0 silently reads all sheets, then fails)\nfor i in range(0, len(wb.sheetnames)):\n    pl.read_excel('f.xlsx', sheet_id=i)\n\n# after\nframes = pl.read_excel('f.xlsx', sheet_id=0)  # dict keyed by sheet name\n# or 1-based: for i in range(1, len(wb.sheetnames) + 1)","handlingStrategy":"validation","validationCode":"import openpyxl\n\nwith openpyxl.load_workbook(src, read_only=True) as wb:\n    n_sheets = len(wb.sheetnames)\nids = [i for i in (sheet_id if isinstance(sheet_id, (list, tuple)) else [sheet_id]) if i]  # 1-based; 0 = all\nassert all(1 <= i <= n_sheets for i in ids), f'sheet_id out of range 1..{n_sheets}'\ndf = pl.read_excel(src, sheet_id=sheet_id)","typeGuard":null,"tryCatchPattern":"try:\n    df = pl.read_excel(src, sheet_id=i)\nexcept ValueError as e:\n    if 'no matching sheet' in str(e):\n        frames = pl.read_excel(src, sheet_id=0, infer_schema_length=1)\n        raise ValueError(f'valid sheet ids: 1..{len(frames)}') from e\n    raise","preventionTips":["sheet_id is 1-based; 0 means 'all sheets' — never loop range(0, n)","Derive id bounds from the actual sheet count (openpyxl sheetnames or a sheet_id=0 probe)","Prefer sheet_name over sheet_id when tabs may be inserted or deleted upstream"],"tags":["polars","excel","ods","sheet-selection","off-by-one","indexing"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}