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 optionsView on GitHub (pinned to df599052da)
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
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
- 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
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
- cannot specify both `sheet_name` ({sheet_name!r}) and `sheet
- no matching sheet found when `sheet_name` is {name!r}
- a more recent version of `fastexcel` is required for 'schema
- table named {table_name!r} not found in sheet {sheet_name!r}
- index {key} is out of bounds for DataFrame of height {num_ro
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/985cee5676f35e53.
Report an issue: GitHub.