pola-rs/polars · error · TypeError

DataFrame object does not support `Series` assignment by ind

Error message

DataFrame object does not support `Series` assignment by index

Use `DataFrame.with_columns`.

What it means

DataFrame.__setitem__ explicitly rejects df['col'] = value (string key). Polars DataFrames are not dict-like mutable containers of Series; in-place column mutation by name is disallowed by design, and the error message redirects to the functional alternative with_columns that returns a new frame.

Source

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

        >>> df
        shape: (3, 2)
        ┌─────┬─────┐
        │ a   ┆ b   │
        │ --- ┆ --- │
        │ i64 ┆ i64 │
        ╞═════╪═════╡
        │ 10  ┆ 30  │
        │ 100 ┆ 50  │
        │ 30  ┆ 60  │
        └─────┴─────┘
        """
        # df["foo"] = series
        if isinstance(key, str):
            msg = (
                "DataFrame object does not support `Series` assignment by index"
                "\n\nUse `DataFrame.with_columns`."
            )
            raise TypeError(msg)

        # df[["C", "D"]]
        elif isinstance(key, list):
            # TODO: Use python sequence constructors
            value = np.array(value)
            if value.ndim != 2:
                msg = "can only set multiple columns with 2D matrix"
                raise ValueError(msg)
            if value.shape[1] != len(key):
                msg = "matrix columns should be equal to list used to determine column names"
                raise ValueError(msg)

            # 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

View on GitHub (pinned to df599052da)

Solutions

  1. Use with_columns: df = df.with_columns(pl.Series('new_col', [1, 2, 3])) or df = df.with_columns((pl.col('existing') * 2).alias('existing'))
  2. For multiple columns: df = df.with_columns(new_a=pl.Series([...]), new_b=...)
  3. Refactor functions to return the new frame instead of mutating: df = annotate(df)

Example fix

# before
df['ratio'] = df['a'] / df['b']

# after
df = df.with_columns((pl.col('a') / pl.col('b')).alias('ratio'))
Defensive patterns

Strategy: validation

Validate before calling

# there is no runtime guard that makes df['col'] = v legal;
# route all column writes through a helper:
def add_col(df, name, values):
    return df.with_columns(pl.Series(name, values))

df = add_col(df, 'ratio', df['a'] / df['b'])

Prevention

When it happens

Trigger: df['new_col'] = [1, 2, 3]; df['existing'] = df['existing'] * 2; df[f'{name}_x'] = series — any assignment whose key is a single string.

Common situations: Direct port of pandas mutation code; notebook-style incremental column addition loops; helper functions that take a df and 'annotate' it in place; duck-typed code shared between pandas and polars.

Related errors


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