pola-rs/polars · error · ParameterCollisionError

the values of `has_header` and `read_options["header_row"]`…

Error message

the values of `has_header` and `read_options["header_row"]` are not compatible

What it means

For the calamine engine, read_options['header_row'] and the top-level has_header flag must agree. ParameterCollisionError is raised when has_header=False but header_row is explicitly set — you cannot both deny a header and name its row.

Solutions

  1. Remove has_header=False and let header_row define the header row, or drop header_row if has_header=False is intended.
  2. Set header_row only when has_header is True (or unset).
  3. Consolidate header configuration into one of the two parameters.

Example fix

// before
pl.read_excel('wb.xlsx', has_header=False, read_options={'header_row': 3})
// after
pl.read_excel('wb.xlsx', read_options={'header_row': 3})
Defensive patterns

Strategy: validation

Validate before calling

if has_header is False and (read_options or {}).get('header_row') is not None:
    raise ValueError('drop either has_header=False or read_options["header_row"]')

Try / catch

from polars.exceptions import ParameterCollisionError
try:
    df = pl.read_excel(src, has_header=False, read_options={'header_row': r})
except ParameterCollisionError:
    df = pl.read_excel(src, read_options={'header_row': r})

Prevention

When it happens

Trigger: pl.read_excel(src, engine='calamine', has_header=False, read_options={'header_row': 3}).

Common situations: Mixing older has_header usage with newer read_options tuning copied from docs or other engines; refactors where one parameter was left behind.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of pola-rs/polars@fe841f959e (2026-09-18). Data as JSON: /api/errors/988f35ef11cdbc5f. Report an issue: GitHub.

Appendix: source

Thrown at py-polars/src/polars/io/spreadsheet/functions.py:745

        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 fe841f959e)