pandas SettingWithCopyWarning (tested on pandas 2 and 3)
SettingWithCopyWarning means an assignment like df[mask]["b"] = 0 was made on a temporary copy, so your DataFrame did not change. pandas 3 removed the warning and shows ChainedAssignmentError instead. We ran the same code on pandas 2.3.3 and 3.1.0.
1. The same code on pandas 2 and pandas 3
import warnings, pandas as pd
warnings.simplefilter("always")
print(pd.__version__)
df = pd.DataFrame({"a": [1, 2, 3], "b": [10, 20, 30]})
df[df["a"] > 1]["b"] = 0 # chained assignment
print(df["b"].tolist())
sub = df[df["a"] > 1]
sub["c"] = 1 # new column on a filtered frame
print(sub.columns.tolist(), df.columns.tolist())
df.loc[df["a"] > 1, "b"] = 0
print(df["b"].tolist())
Output with pandas 2.3.3:
/w/b1.py:5: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df[df["a"] > 1]["b"] = 0 # chained assignment
/w/b1.py:8: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
sub["c"] = 1 # new column on a filtered frame
2.3.3
[10, 20, 30]
['a', 'b', 'c'] ['a', 'b']
[10, 0, 0]
Output with pandas 3.1.0:
/w/b1.py:5: ChainedAssignmentError: A value is being set on a copy of a DataFrame or Series through chained assignment.
Such chained assignment never works to update the original DataFrame or Series, because the intermediate object on which we are setting values always behaves as a copy (due to Copy-on-Write).
Try using '.loc[row_indexer, col_indexer] = value' instead, to perform the assignment in a single step.
See the documentation for a more detailed explanation: https://pandas.pydata.org/docs/dev/user_guide/migration.html#chained-assignment
df[df["a"] > 1]["b"] = 0 # chained assignment
3.1.0
[10, 20, 30]
['a', 'b', 'c'] ['a', 'b']
[10, 0, 0]
2. What the warning means
df[mask]["b"] = 0 is two steps: df[mask] builds a new object, then ["b"] = 0 sets values on that object. The original df is not changed on either version (the second line of output is still [10, 20, 30]). pandas 2 warns with SettingWithCopyWarning. pandas 3 enables Copy-on-Write, removes SettingWithCopyWarning, and shows ChainedAssignmentError instead. Despite the name it is a warning, not an exception, so the script keeps running with unchanged data.
3. Fix: one .loc assignment
df.loc[mask, "b"] = 0 selects and sets in a single step, so it updates df on both versions (last output line: [10, 0, 0]). Do not just silence the warning: the assignment it warns about did nothing.
4. Adding a column to a filtered DataFrame
sub = df[mask]; sub["c"] = 1 warns on pandas 2 even though it is usually what you meant: a new column on sub only. pandas 3 is silent because sub now always behaves as an independent copy. To make that explicit on pandas 2 and remove the warning, write sub = df[mask].copy().
Related: all pandas 3 breaking changes · KeyError: 0 in pandas · name 'pd' is not defined.
Frequently asked questions
How do I fix SettingWithCopyWarning?
Assign in one step with df.loc[row_mask, 'col'] = value. If you meant to work on a separate subset, take it with .copy().
Does pandas 3 still show SettingWithCopyWarning?
No. With Copy-on-Write, chained assignment shows ChainedAssignmentError (a warning) and still does not change the original DataFrame.
Should I just suppress SettingWithCopyWarning?
No: the warned-about assignment did not update your DataFrame. Fix it with .loc or .copy().
Written with AI assistance. Measured on 2026-10-23 in the python:3-alpine Docker image (Python 3.14) with pandas 2.3.3 and pandas 3.1.0: chained assignment, a new column on a filtered frame, and the .loc fix. The block was run verbatim on both versions and the output pasted unedited. PlainHeaders is our extension; Python and pandas are free.