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
- Always pass the parent: pl.write_excel(df, workbook=wb, worksheet=ws).
- Or drop the worksheet object and use its name: pl.write_excel(df, workbook='out.xlsx', worksheet='Sheet1').
- 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
- A Worksheet handle is only usable together with workbook=<its Workbook>.
- If you only have a sheet name, pass the string — polars resolves it inside the workbook/path target.
- Never mix worksheet objects with workbook as a path, None, or BytesIO.
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
- the given workbook object {wb.filename!r} is not the parent
- invalid dtype_format value: {fmt!r} (expected format string,
- cannot create a second {col!r} column
- supplying 'columns' param value is mandatory for sparklines
- sparkline data range/cols must all be adjacent
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/6907b124b2c7d7c3.
Report an issue: GitHub.