pola-rs/polars · error · FileNotFoundError

no workbook found at path {src!r}

Error message

no workbook found at path {src!r}

What it means

FileNotFoundError raised while normalizing read_excel sources. When a str/PathLike source does not exist as a literal path, polars expands '~' and treats it as a glob pattern (glob.glob(src, recursive=True)); if the pattern matches nothing, the file was neither a real path, a URL, nor a matching glob, so reading cannot proceed. Note this fire-once message names the expanded pattern.

Source

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

    read_multiple_workbooks = True
    sources: list[Any] = []

    if isinstance(source, memoryview):
        source = source.tobytes()
    if not isinstance(source, Sequence) or isinstance(source, (bytes, str)):
        read_multiple_workbooks = False
        source = [source]  # type: ignore[assignment]

    for src in source:  # type: ignore[union-attr]
        if isinstance(src, (str, os.PathLike)) and not Path(src).exists():
            src = os.path.expanduser(str(src))  # noqa: PTH111
            if looks_like_url(src):
                sources.append(src)
                continue
            sources.extend(files := glob(src, recursive=True))  # noqa: PTH207
            if not files:
                msg = f"no workbook found at path {src!r}"
                raise FileNotFoundError(msg)
            read_multiple_workbooks = True
        else:
            if isinstance(src, os.PathLike):
                src = str(src)
            sources.append(src)

    return sources, read_multiple_workbooks


def _standardize_duplicates(s: str) -> str:
    """Standardize columns with '_duplicated_n' names."""
    return re.sub(r"_duplicated_(\d+)", repl=r"\1", string=s)


def _unpack_read_results(
    frames: list[pl.DataFrame] | list[dict[str, pl.DataFrame]],
    *,
    read_multiple_workbooks: bool,

View on GitHub (pinned to df599052da)

Solutions

  1. If the filename is literal, check it exists first and escape metacharacters: src = glob.escape('data[1].xlsx') or pass a resolved Path after verifying Path(src).exists().
  2. If it should be a glob, verify the pattern and working directory: print(glob.glob(pattern, recursive=True)) before calling read_excel.
  3. For URLs, ensure the string is recognized as such (full https://... form) so it is not glob-expanded.
  4. Guard with if not Path(src).exists() and not glob.glob(src): raise a clearer error with the intended location.

Example fix

# before
pl.read_excel('data[1].xlsx')  # file exists, but '[' breaks the glob fallback

# after
import glob, pathlib
src = 'data[1].xlsx'
assert pathlib.Path(src).exists()
pl.read_excel(glob.escape(src) if any(c in src for c in '[]*?') else src)
Defensive patterns

Strategy: validation

Validate before calling

import glob, os
from pathlib import Path

def resolve_excel_source(src: str) -> str:
    if Path(src).exists():
        return src
    expanded = os.path.expanduser(src)
    if Path(expanded).exists():
        return expanded
    if glob.glob(expanded, recursive=True):
        return expanded
    raise FileNotFoundError(f'no workbook at {src!r} (exists={Path(src).exists()})')

pl.read_excel(resolve_excel_source(src))

Try / catch

try:
    df = pl.read_excel(src)
except FileNotFoundError as e:
    if 'no workbook found at path' in str(e):
        raise ValueError(f'check path/glob {src!r}: cwd={os.getcwd()}') from e
    raise

Prevention

When it happens

Trigger: pl.read_excel('~/reports/data_2024_*.xlsx') matching nothing; pl.read_excel('data[1].xlsx') where the literal file exists but '[' makes it an invalid/empty glob character class; plain wrong paths.

Common situations: Filenames containing glob metacharacters ([, ], *, ?) — very common with bracketed indices or dates; running on a different OS where the path separator or expansion differs; typos or files not yet downloaded; passing Path objects to files created asynchronously.

Related errors


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