datarekha
Pandas & Data Wrangling Medium Asked at AirbnbAsked at LinkedInAsked at Stripe

What causes SettingWithCopyWarning in pandas and how do you fix it?

The short answer

SettingWithCopyWarning fires when you try to set a value on what pandas suspects is a copy of a slice rather than the original DataFrame, so the write may silently fail. The fix is to always use .loc on the original DataFrame for assignments, or call .copy() explicitly when you intend to work on a detached copy.

How to think about it

This question separates people who memorized a fix from people who understand the failure. What the warning is really flagging is uncertainty: pandas can’t always tell whether a slice shares memory with the original frame (a view) or stands apart from it (a copy). The genuinely confusing part is that it isn’t always an error — sometimes the write lands anyway. When you chain two indexing operations like df[mask]["col"] = value, the first [] builds an intermediate object and the second [] writes into that. If the intermediate turned out to be a copy, your assignment vanishes with no exception — and you only find out when the downstream numbers are wrong.

You cannot reliably predict which you’ll get, because pandas returns views or copies depending on the operation and the memory layout underneath. So the fix isn’t to guess better — it’s to never chain. State your intent in a single operation and the ambiguity disappears.

The fix, with the result it produces

There are exactly two correct patterns: write to the original with one .loc call, or detach a .copy() first and work on that. This runs both and prints the proof:

import pandas as pd

df = pd.DataFrame({
    "name":  ["Alice", "Bob", "Carol", "Dave"],
    "score": [85, 42, 91, 38],
    "grade": ["B", "F", "A", "F"],
})

# BAD: df[df["score"] < 50]["grade"] = "FAIL"  — chained, may write to a copy

# GOOD: single .loc call, always writes to the original
df.loc[df["score"] < 50, "grade"] = "FAIL"
print("After .loc assignment:")
print(df)
print()

# ALSO GOOD: explicit .copy() for a detached working frame
low_scorers = df[df["score"] < 50].copy()
low_scorers["grade"] = "NEEDS REVIEW"   # touches low_scorers, never df
print("Detached copy (df is unchanged):")
print(low_scorers)
After .loc assignment:
    name  score grade
0  Alice     85     B
1    Bob     42  FAIL
2  Carol     91     A
3   Dave     38  FAIL

Detached copy (df is unchanged):
   name  score         grade
1   Bob     42  NEEDS REVIEW
3   Dave     38  NEEDS REVIEW

The .loc form located the rows and assigned in one operation, so Bob and Dave flip to FAIL in df itself — no warning, no doubt. The .copy() form rewrote low_scorers to NEEDS REVIEW while df stayed exactly as the first block left it. One mutates the source; the other works on a deliberate detachment. Both are unambiguous, which is precisely why neither warns. The rule to carry away: one [] to locate, one assignment — never two [][] with a write in between.

It’s worth knowing where this is headed. pandas 2.0 introduced opt-in Copy-on-Write, and in pandas 3.0 it becomes the default. Under CoW every subset is always a copy, so df[mask]["col"] = value does nothing to df — the silent corruption turns into an obvious no-op you’ll catch immediately. You can switch it on today with pd.options.mode.copy_on_write = True, and code already written with explicit .loc assignments stays correct whether CoW is on or off.

Learn it properly SettingWithCopyWarning — fixed

Keep practising

All Pandas & Data Wrangling questions

Explore further

Skip to content