{"record":{"id":"4903d8093904e147","repo":"pola-rs/polars","slug":"unexpected-column-selection-col-selection-r","errorCode":null,"errorMessage":"unexpected column selection {col_selection!r}","messagePattern":"unexpected column selection (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/dataframe/frame.py","lineNumber":1587,"sourceCode":"            row_selection, col_selection = key\n\n            if (\n                isinstance(row_selection, pl.Series) and row_selection.dtype == Boolean\n            ) or is_bool_sequence(row_selection):\n                msg = (\n                    \"not allowed to set DataFrame by boolean mask in the row position\"\n                    \"\\n\\nConsider using `DataFrame.with_columns`.\"\n                )\n                raise TypeError(msg)\n\n            # get series column selection\n            if isinstance(col_selection, str):\n                s = self.__getitem__(col_selection)\n            elif isinstance(col_selection, int):\n                s = self[:, col_selection]\n            else:\n                msg = f\"unexpected column selection {col_selection!r}\"\n                raise TypeError(msg)\n\n            # dispatch to __setitem__ of Series to do modification\n            s[row_selection] = value\n\n            # now find the location to place series\n            # df[idx]\n            if isinstance(col_selection, int):\n                self.replace_column(col_selection, s)\n            # df[\"foo\"]\n            elif isinstance(col_selection, str):\n                self._replace(col_selection, s)\n        else:\n            msg = (\n                f\"cannot use `__setitem__` on DataFrame\"\n                f\" with key {key!r} of type {type(key).__name__!r}\"\n                f\" and value {value!r} of type {type(value).__name__!r}\"\n            )\n            raise TypeError(msg)","sourceCodeStart":1569,"sourceCodeEnd":1605,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/dataframe/frame.py#L1569-L1605","documentation":"Raised by DataFrame.__setitem__ when assigning with a tuple key `df[row, col] = value` where the column part is neither a str (column name) nor an int (column index). Polars dispatches str to column lookup by name and int to positional `self[:, col]`; any other object (list, slice, Series, range, ndarray) cannot identify a single target column, so it refuses the assignment. Use with_columns / insert_column for anything beyond a single scalar cell or column.","triggerScenarios":"Calling `df[0, [1, 2]] = value`, `df[2, 'a':'c'] = value`, `df[0, pl.Series('a',[1,2])] = 5`, or `df[1, range(2)] = 0` — i.e. any 2-tuple setitem whose second element is not a str or int. Also `df[0, (1,)] = x` or passing a numpy array as col_selection.","commonSituations":"Porting pandas code where `df.loc[0, ['a','b']] = ...` was legal; attempting to set a whole row with `df[0, :] = vals`; dynamically computing a column key that ends up as a list/tuple instead of a single name; slicing columns positionally with `df[0, 1:3] = ...`.","solutions":["Set one cell at a time with a str or int column key: `df[row, 'col'] = v` or `df[row, 0] = v`","To set multiple columns at once, use `df.with_columns(...)` or assign via a list key with a 2D numpy value: `df[['a','b']] = np.array(...)`","To set a whole row, use `df.row(i)` to read and reconstruct, or rebuild the frame with with_columns on the underlying expressions","If the column key comes from dynamic code, coerce it first: `col = cols[0]` or `col = df.columns.index(name)` before the setitem"],"exampleFix":"# before\ndf[0, [1, 2]] = [10, 20]\n\n# after\ndf[0, 1] = 10\ndf[0, 2] = 20\n# or set whole columns:\ndf = df.with_columns(pl.lit(10).alias('b'), pl.lit(20).alias('c'))","handlingStrategy":"type-guard","validationCode":"def valid_cell_key(df: pl.DataFrame, key: tuple) -> bool:\n    if not (isinstance(key, tuple) and len(key) == 2):\n        return False\n    _, col = key\n    return isinstance(col, (str, int)) and not isinstance(col, bool)","typeGuard":"from typing import Union\n\ndef is_column_selector(col: object) -> bool:\n    \"\"\"True only for the str/int column selectors DataFrame.__setitem__ accepts.\"\"\"\n    if isinstance(col, bool):\n        return False\n    if isinstance(col, str):\n        return True\n    return isinstance(col, int)","tryCatchPattern":"try:\n    df[row, col] = value\nexcept TypeError as e:\n    if 'unexpected column selection' in str(e):\n        raise ValueError(f'bad column key {col!r}; use str or int') from e\n    raise","preventionTips":["Normalize dynamic column keys to a single str name or int index before df[row, col] = value","For multi-column writes, use with_columns or the df[[names]] = 2D-array form instead of tuple keys","Ban slices, lists, and Series as the column part of setitem keys in code review"],"tags":["dataframe","setitem","type-guard","column-selection"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}