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_header

View on GitHub (pinned to df599052da)

Solutions

  1. Delete the 'columns' key from read_options and keep only the top-level columns parameter
  2. Alternatively drop the top-level columns argument and keep read_options['columns'] (less idiomatic)
  3. 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

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


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