pola-rs/polars · error · ParameterCollisionError
cannot specify both `columns` and `read_options["columns"]`
Error message
cannot specify both `columns` and `read_options["columns"]`
What it means
Raised by polars.read_excel (engine='xlsx2csv') in _get_read_options when column selection is supplied twice: once via the top-level `columns` parameter and once via the `read_options['columns']` key (which is forwarded to the internal read_csv call). polars refuses to guess which selection wins, so it raises ParameterCollisionError (a PolarsError subclass, NOT a ValueError). The xlsx2csv engine converts the sheet to CSV and reads it with read_csv, which is why csv-level keys like 'columns' can appear in read_options at all.
Source
Thrown at py-polars/src/polars/io/spreadsheet/functions.py:757
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 (
"has_header" in read_options
and read_options["has_header"] is not has_header
):
msg = 'the values of `has_header` and `read_options["has_header"]` are not compatible'
raise ParameterCollisionError(msg)
elif ("infer_schema_length" in read_options) and (
infer_schema_length != N_INFER_DEFAULT
):
msg = 'cannot specify both `infer_schema_length` and `read_options["infer_schema_length"]`'
raise ParameterCollisionError(msg)
read_options["infer_schema_length"] = infer_schema_length
if "has_header" not in read_options:
read_options["has_header"] = has_header
else:
read_options["infer_schema_length"] = infer_schema_length
read_options["has_header"] = has_headerView on GitHub (pinned to df599052da)
Solutions
- Delete the 'columns' key from read_options and keep only the top-level columns parameter
- Alternatively drop the top-level columns argument and keep read_options['columns'] (less idiomatic)
- Audit read_options for other duplicated polars-level params (has_header, infer_schema_length) while you are there
Example fix
# before
pl.read_excel('f.xlsx', engine='xlsx2csv', columns=['a', 'b'], read_options={'columns': ['a', 'b'], 'truncate_ragged_lines': True})
# after
pl.read_excel('f.xlsx', engine='xlsx2csv', columns=['a', 'b'], read_options={'truncate_ragged_lines': True}) Defensive patterns
Strategy: validation
Validate before calling
def check_xlsx2csv_columns(columns, read_options):
if columns and 'columns' in (read_options or {}):
raise ValueError("pass column selection either via `columns` or read_options['columns'], not both")
check_xlsx2csv_columns(columns, read_options)
df = pl.read_excel(src, engine='xlsx2csv', columns=columns, read_options=read_options) Try / catch
from polars.exceptions import ParameterCollisionError
try:
df = pl.read_excel(src, engine='xlsx2csv', columns=cols, read_options=opts)
except ParameterCollisionError as e:
# ParameterCollisionError is a PolarsError, NOT a ValueError
raise ValueError(f'bad read_options for xlsx2csv: {e}') from e Prevention
- Reserve read_options for engine/csv-specific keys; express polars-level concerns (columns, has_header, infer_schema_length) only via top-level parameters
- Centralize read_options construction in one helper that asserts it contains no polars-level keys
- Remember ParameterCollisionError subclasses PolarsError, so except ValueError will not catch it
When it happens
Trigger: pl.read_excel('f.xlsx', engine='xlsx2csv', columns=['a','b'], read_options={'columns': ['a','b'], ...}) — i.e. a truthy top-level columns argument AND the key 'columns' present in the read_options dict. Fires before any file parsing starts.
Common situations: Copy-pasting a batch of read_csv kwargs into read_options while also using the polars-level `columns` parameter; migrating older code that selected columns via csv options; wrapper functions that merge a user dict into read_options and also expose `columns`.
Related errors
- the values of `has_header` and `read_options["has_header"]`
- cannot specify both `infer_schema_length` and `read_options[
- cannot specify columns in both `schema_overrides` and `read_
- the `columns` argument should contain a list of all integers
- a more recent version of `fastexcel` is required for 'use_co
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/57f6628d3d3cc3d5.
Report an issue: GitHub.