pola-rs/polars · error · TypeError

worksheet object requires the parent workbook object; found

Error message

worksheet object requires the parent workbook object; found workbook={workbook!r}

What it means

TypeError raised by _xl_setup_workbook during write_excel when worksheet is an xlsxwriter Worksheet object but the workbook parameter is not the corresponding xlsxwriter Workbook. A live worksheet handle is only meaningful relative to its owning workbook; if workbook is None, a path, a BytesIO, or anything else, polars would have to create a new workbook that cannot contain that worksheet, so it refuses.

Source

Thrown at py-polars/src/polars/io/spreadsheet/_write_utils.py:611

    from xlsxwriter.worksheet import Worksheet

    if isinstance(workbook, Workbook):
        wb, can_close = workbook, False
        ws = (
            worksheet
            if (
                isinstance(worksheet, Worksheet)
                and _xl_worksheet_in_workbook(wb, worksheet)
            )
            # Argument `Worksheet | str | None` is not assignable to parameter `name`
            # with type `str`.
            else wb.get_worksheet_by_name(
                name=worksheet  # pyrefly: ignore[bad-argument-type]
            )
        )
    elif isinstance(worksheet, Worksheet):
        msg = f"worksheet object requires the parent workbook object; found workbook={workbook!r}"
        raise TypeError(msg)
    else:
        workbook_options = {
            "use_zip64": use_zip64,
            "nan_inf_to_errors": True,
            "strings_to_formulas": False,
            "default_date_format": _XL_DEFAULT_DTYPE_FORMATS_[Date],
        }
        if isinstance(workbook, BytesIO):
            wb, ws, can_close = Workbook(workbook, workbook_options), None, True
        else:
            file: Path | IO[bytes]
            if workbook is None:
                file = Path("dataframe.xlsx")
            elif isinstance(workbook, str):
                file = Path(workbook)
            else:
                file = workbook

View on GitHub (pinned to df599052da)

Solutions

  1. Always pass the parent: pl.write_excel(df, workbook=wb, worksheet=ws).
  2. Or drop the worksheet object and use its name: pl.write_excel(df, workbook='out.xlsx', worksheet='Sheet1').
  3. In helper functions, require workbook and worksheet to be passed as a pair (or derive the sheet by name only).

Example fix

# before
ws = wb.add_worksheet('data')
pl.write_excel(df, worksheet=ws)  # workbook missing

# after
pl.write_excel(df, workbook=wb, worksheet=ws)
Defensive patterns

Strategy: type-guard

Validate before calling

from xlsxwriter import Workbook
from xlsxwriter.worksheet import Worksheet

if isinstance(worksheet, Worksheet) and not isinstance(workbook, Workbook):
    raise TypeError('worksheet object requires its parent Workbook in `workbook=`')
pl.write_excel(df, workbook=workbook, worksheet=worksheet)

Type guard

import xlsxwriter

def has_parent_workbook(workbook: object, worksheet: object) -> bool:
    return not isinstance(worksheet, xlsxwriter.worksheet.Worksheet) or isinstance(workbook, xlsxwriter.Workbook)

Try / catch

try:
    pl.write_excel(df, worksheet=ws)
except TypeError as e:
    if 'requires the parent workbook object' in str(e):
        pl.write_excel(df, workbook=ws._parent if hasattr(ws, '_parent') else None, worksheet=ws)
    else:
        raise

Prevention

When it happens

Trigger: pl.write_excel(df, worksheet=ws) with no workbook argument; or pl.write_excel(df, workbook=BytesIO(), worksheet=ws); or workbook='out.xlsx' (a path) together with a worksheet object.

Common situations: Reusing a worksheet obtained from wb.get_worksheet_by_name()/add_worksheet() but forgetting to pass wb back in; switching the workbook target from an object to a file path/BytesIO while keeping the worksheet handle; helper functions that accept an optional worksheet without threading the workbook through.

Related errors


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