pola-rs/polars · error · TypeError

unexpected column selection {col_selection!r}

Error message

unexpected column selection {col_selection!r}

What it means

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.

Source

Thrown at py-polars/src/polars/dataframe/frame.py:1587

            row_selection, col_selection = key

            if (
                isinstance(row_selection, pl.Series) and row_selection.dtype == Boolean
            ) or is_bool_sequence(row_selection):
                msg = (
                    "not allowed to set DataFrame by boolean mask in the row position"
                    "\n\nConsider using `DataFrame.with_columns`."
                )
                raise TypeError(msg)

            # get series column selection
            if isinstance(col_selection, str):
                s = self.__getitem__(col_selection)
            elif isinstance(col_selection, int):
                s = self[:, col_selection]
            else:
                msg = f"unexpected column selection {col_selection!r}"
                raise TypeError(msg)

            # dispatch to __setitem__ of Series to do modification
            s[row_selection] = value

            # now find the location to place series
            # df[idx]
            if isinstance(col_selection, int):
                self.replace_column(col_selection, s)
            # df["foo"]
            elif isinstance(col_selection, str):
                self._replace(col_selection, s)
        else:
            msg = (
                f"cannot use `__setitem__` on DataFrame"
                f" with key {key!r} of type {type(key).__name__!r}"
                f" and value {value!r} of type {type(value).__name__!r}"
            )
            raise TypeError(msg)

View on GitHub (pinned to df599052da)

Solutions

  1. Set one cell at a time with a str or int column key: `df[row, 'col'] = v` or `df[row, 0] = v`
  2. 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(...)`
  3. To set a whole row, use `df.row(i)` to read and reconstruct, or rebuild the frame with with_columns on the underlying expressions
  4. If the column key comes from dynamic code, coerce it first: `col = cols[0]` or `col = df.columns.index(name)` before the setitem

Example fix

# before
df[0, [1, 2]] = [10, 20]

# after
df[0, 1] = 10
df[0, 2] = 20
# or set whole columns:
df = df.with_columns(pl.lit(10).alias('b'), pl.lit(20).alias('c'))
Defensive patterns

Strategy: type-guard

Validate before calling

def valid_cell_key(df: pl.DataFrame, key: tuple) -> bool:
    if not (isinstance(key, tuple) and len(key) == 2):
        return False
    _, col = key
    return isinstance(col, (str, int)) and not isinstance(col, bool)

Type guard

from typing import Union

def is_column_selector(col: object) -> bool:
    """True only for the str/int column selectors DataFrame.__setitem__ accepts."""
    if isinstance(col, bool):
        return False
    if isinstance(col, str):
        return True
    return isinstance(col, int)

Try / catch

try:
    df[row, col] = value
except TypeError as e:
    if 'unexpected column selection' in str(e):
        raise ValueError(f'bad column key {col!r}; use str or int') from e
    raise

Prevention

When it happens

Trigger: 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.

Common situations: 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] = ...`.

Related errors


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