{"record":{"id":"a7a83a62896ed6df","repo":"pola-rs/polars","slug":"cannot-specify-both-columns-and-read-options-u","errorCode":null,"errorMessage":"cannot specify both `columns` and `read_options[\"use_columns\"]`","messagePattern":"cannot specify both `columns` and `read_options\\[\"use_columns\"\\]`","errorType":"exception","errorClass":"ParameterCollisionError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/io/spreadsheet/functions.py","lineNumber":740,"sourceCode":"        return parsed_sheets\n    return next(iter(parsed_sheets.values()))\n\n\ndef _get_read_options(\n    read_options: dict[str, Any] | None,\n    *,\n    engine: ExcelSpreadsheetEngine,\n    columns: Sequence[int] | Sequence[str] | None,\n    infer_schema_length: int | None,\n    has_header: bool,\n) -> dict[str, Any]:\n    \"\"\"Normalise top-level parameters to engine-specific 'read_options' dict.\"\"\"\n    read_options = (read_options or {}).copy()\n\n    if engine == \"calamine\":\n        if (\"use_columns\" in read_options) and columns:\n            msg = 'cannot specify both `columns` and `read_options[\"use_columns\"]`'\n            raise ParameterCollisionError(msg)\n        elif read_options.get(\"header_row\") is not None and has_header is False:\n            msg = 'the values of `has_header` and `read_options[\"header_row\"]` are not compatible'\n            raise ParameterCollisionError(msg)\n        elif (\"schema_sample_rows\" in read_options) and (\n            infer_schema_length != N_INFER_DEFAULT\n        ):\n            msg = 'cannot specify both `infer_schema_length` and `read_options[\"schema_sample_rows\"]`'\n            raise ParameterCollisionError(msg)\n\n        read_options[\"schema_sample_rows\"] = infer_schema_length\n        if has_header is False and \"header_row\" not in read_options:\n            read_options[\"header_row\"] = None\n\n    elif engine == \"xlsx2csv\":\n        if (\"columns\" in read_options) and columns:\n            msg = 'cannot specify both `columns` and `read_options[\"columns\"]`'\n            raise ParameterCollisionError(msg)\n        elif (","sourceCodeStart":722,"sourceCodeEnd":758,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/io/spreadsheet/functions.py#L722-L758","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\npl.read_excel('f.xlsx', columns=['a', 'b'], read_options={'use_columns': [0, 1]})\n\n# after\npl.read_excel('f.xlsx', columns=['a', 'b'])","handlingStrategy":"validation","validationCode":"if engine == 'calamine':\n    if columns and 'use_columns' in (read_options or {}):\n        (read_options or {}).pop('use_columns')  # keep the top-level param\npl.read_excel(path, engine=engine, columns=columns, read_options=read_options)","typeGuard":null,"tryCatchPattern":"try:\n    pl.read_excel(path, columns=columns, read_options=read_options)\nexcept pl.exceptions.ParameterCollisionError as e:\n    if 'use_columns' in str(e):\n        ro = {k: v for k, v in (read_options or {}).items() if k != 'use_columns'}\n        pl.read_excel(path, columns=columns, read_options=ro)\n    else:\n        raise","preventionTips":["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."],"tags":["excel","spreadsheet","read-excel","calamine","parameter-conflict"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}