pola-rs/polars · error · ParameterCollisionError
cannot specify both `columns` and `read_options["use_columns
Error message
cannot specify both `columns` and `read_options["use_columns"]`
What it means
polars.exceptions.ParameterCollisionError raised while normalizing read_excel options for the calamine engine. The top-level columns parameter and the engine-level read_options['use_columns'] both select which columns to load; supplying both would make precedence ambiguous, so polars rejects the combination during option normalization, before parsing starts.
Source
Thrown at py-polars/src/polars/io/spreadsheet/functions.py:740
return parsed_sheets
return next(iter(parsed_sheets.values()))
def _get_read_options(
read_options: dict[str, Any] | None,
*,
engine: ExcelSpreadsheetEngine,
columns: Sequence[int] | Sequence[str] | None,
infer_schema_length: int | None,
has_header: bool,
) -> dict[str, Any]:
"""Normalise top-level parameters to engine-specific 'read_options' dict."""
read_options = (read_options or {}).copy()
if engine == "calamine":
if ("use_columns" in read_options) and columns:
msg = 'cannot specify both `columns` and `read_options["use_columns"]`'
raise ParameterCollisionError(msg)
elif read_options.get("header_row") is not None and has_header is False:
msg = 'the values of `has_header` and `read_options["header_row"]` are not compatible'
raise ParameterCollisionError(msg)
elif ("schema_sample_rows" in read_options) and (
infer_schema_length != N_INFER_DEFAULT
):
msg = 'cannot specify both `infer_schema_length` and `read_options["schema_sample_rows"]`'
raise ParameterCollisionError(msg)
read_options["schema_sample_rows"] = infer_schema_length
if has_header is False and "header_row" not in read_options:
read_options["header_row"] = None
elif engine == "xlsx2csv":
if ("columns" in read_options) and columns:
msg = 'cannot specify both `columns` and `read_options["columns"]`'
raise ParameterCollisionError(msg)
elif (View on GitHub (pinned to df599052da)
Solutions
- Keep the top-level parameter: pl.read_excel(..., columns=['A', 'B']) and delete 'use_columns' from read_options.
- Or keep it engine-level: pass read_options={'use_columns': [0, 1]} and drop columns — useful when the same read_options dict is reused with the raw calamine reader.
- In wrappers, pop one of the two before delegating to read_excel.
Example fix
# before
pl.read_excel('f.xlsx', columns=['a', 'b'], read_options={'use_columns': [0, 1]})
# after
pl.read_excel('f.xlsx', columns=['a', 'b']) Defensive patterns
Strategy: validation
Validate before calling
if engine == 'calamine':
if columns and 'use_columns' in (read_options or {}):
(read_options or {}).pop('use_columns') # keep the top-level param
pl.read_excel(path, engine=engine, columns=columns, read_options=read_options) Try / catch
try:
pl.read_excel(path, columns=columns, read_options=read_options)
except pl.exceptions.ParameterCollisionError as e:
if 'use_columns' in str(e):
ro = {k: v for k, v in (read_options or {}).items() if k != 'use_columns'}
pl.read_excel(path, columns=columns, read_options=ro)
else:
raise Prevention
- Pick one layer for column selection: polars top-level params or engine read_options — never both.
- Keep engine-specific option dicts separate per engine instead of one shared dict.
- When porting python-calamine code, strip use_columns in favor of columns.
When it happens
Trigger: pl.read_excel('f.xlsx', engine='calamine', columns=['A', 'B'], read_options={'use_columns': [0, 1]}). Any truthy columns together with a 'use_columns' key present in read_options.
Common situations: Migrating calamine (python-calamine) example code that used use_columns into polars' read_excel while keeping the polars-style columns argument; teams mixing both styles in shared helper functions.
Related errors
- the values of `has_header` and `read_options["header_row"]`
- cannot specify both `infer_schema_length` and `read_options[
- no workbook found at path {src!r}
- no data found in the given workbook(s) and sheet(s)
- no matching sheets found when `sheet_{param}` is {value!r}
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/a7a83a62896ed6df.
Report an issue: GitHub.