pola-rs/polars · error · TypeError

not allowed to set DataFrame by boolean mask in the row posi

Error message

not allowed to set DataFrame by boolean mask in the row position

Consider using `DataFrame.with_columns`.

What it means

DataFrame.__setitem__ with a (row, col) tuple key rejects boolean row selectors: a pl.Series with Boolean dtype or a list of bools. Mask-based cell assignment would require hidden, order-dependent copying and is intentionally unsupported; the error redirects to with_columns for conditional updates.

Source

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

            # TODO: we can parallelize this by calling from_numpy
            columns = []
            for i, name in enumerate(key):
                columns.append(pl.Series(name, value[:, i]))
            self._df = self.with_columns(columns)._df

        # df[a, b]
        elif isinstance(key, tuple):
            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"]

View on GitHub (pinned to df599052da)

Solutions

  1. Use conditional expression: df = df.with_columns(pl.when(pl.col('a') > 1).then(-1).otherwise(pl.col('a')).alias('a'))
  2. With an external boolean Series mask: df = df.with_columns(pl.when(pl.Series(mask)).then(value).otherwise(pl.col('a')).alias('a'))
  3. To set by integer positions, use row-selection with integers/ranges instead of masks

Example fix

# before
df[df['qty'] < 0, 'qty'] = 0

# after
df = df.with_columns(
    pl.when(pl.col('qty') < 0).then(0).otherwise(pl.col('qty')).alias('qty')
)
Defensive patterns

Strategy: validation

Validate before calling

# masks are rejected by design; express the conditional update declaratively instead
df = df.with_columns(
    pl.when(pl.col('qty') < 0).then(0).otherwise(pl.col('qty')).alias('qty')
)

Type guard

import polars as pl

def is_boolean_row_selection(sel: object) -> bool:
    return (isinstance(sel, pl.Series) and sel.dtype == pl.Boolean) or (
        isinstance(sel, list) and all(isinstance(v, bool) for v in sel)
    )
# if is_boolean_row_selection(row_sel): use pl.when(...) instead of __setitem__

Prevention

When it happens

Trigger: df[mask_series, 'col'] = value where mask_series.dtype == pl.Boolean; df[[True, False, ...], 5] = 0; df[df['a'] > 1, 'a'] = -1.

Common situations: Ported pandas conditional assignment (df.loc[df.a > 1, 'a'] = v pattern); sentinel/replacement loops that try to zero out flagged rows; validation code marking bad cells by mask.

Related errors


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