pola-rs/polars · error · ValueError

no matching sheet found when `sheet_id` is {idx}

Error message

no matching sheet found when `sheet_id` is {idx}

What it means

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.

Source

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

            (sheet_name,) if isinstance(sheet_name, str) else sheet_name or ()
        ):
            known_sheet_names = {ws["name"] for ws in worksheets}
            for name in names:
                if name not in known_sheet_names:
                    msg = f"no matching sheet found when `sheet_name` is {name!r}"
                    raise ValueError(msg)
                sheet_names.append(name)
        else:
            ids = (sheet_id,) if isinstance(sheet_id, int) else sheet_id or ()
            sheet_names_by_idx = {
                idx: ws["name"]
                for idx, ws in enumerate(worksheets, start=1)
                if (sheet_id == 0 or ws["index"] in ids or ws["name"] in names)
            }
            for idx in ids:
                if (name := sheet_names_by_idx.get(idx)) is None:
                    msg = f"no matching sheet found when `sheet_id` is {idx}"
                    raise ValueError(msg)
                sheet_names.append(name)

    return sheet_names, return_multiple_sheets  # type: ignore[return-value]


def _initialise_spreadsheet_parser(
    engine: str | None,
    source: str | IO[bytes] | bytes,
    engine_options: dict[str, Any],
) -> tuple[Callable[..., pl.DataFrame], Any, list[dict[str, Any]]]:
    """Instantiate the indicated spreadsheet parser and establish related properties."""
    if isinstance(source, str) and not Path(source).exists():
        raise FileNotFoundError(source)

    if engine == "xlsx2csv":  # default
        xlsx2csv = import_optional("xlsx2csv")

        # establish sensible defaults for unset options

View on GitHub (pinned to df599052da)

Solutions

  1. Use 1-based ids and verify against the sheet count before calling
  2. If you need everything, use sheet_id=0 once and index the returned {sheet_name: DataFrame} dict
  3. Handle dynamic layouts by reading sheet names first (openpyxl sheetnames) instead of guessing ids

Example fix

# before (0-based assumption; id 0 silently reads all sheets, then fails)
for i in range(0, len(wb.sheetnames)):
    pl.read_excel('f.xlsx', sheet_id=i)

# after
frames = pl.read_excel('f.xlsx', sheet_id=0)  # dict keyed by sheet name
# or 1-based: for i in range(1, len(wb.sheetnames) + 1)
Defensive patterns

Strategy: validation

Validate before calling

import openpyxl

with openpyxl.load_workbook(src, read_only=True) as wb:
    n_sheets = len(wb.sheetnames)
ids = [i for i in (sheet_id if isinstance(sheet_id, (list, tuple)) else [sheet_id]) if i]  # 1-based; 0 = all
assert all(1 <= i <= n_sheets for i in ids), f'sheet_id out of range 1..{n_sheets}'
df = pl.read_excel(src, sheet_id=sheet_id)

Try / catch

try:
    df = pl.read_excel(src, sheet_id=i)
except ValueError as e:
    if 'no matching sheet' in str(e):
        frames = pl.read_excel(src, sheet_id=0, infer_schema_length=1)
        raise ValueError(f'valid sheet ids: 1..{len(frames)}') from e
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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