Python

pandas SettingWithCopyWarning: a write may be lost

Written and reviewed by Sahil Srivastav

PythonpandasData correctness
/usr/local/lib/python3.12/site-packages/pandas/core/indexing.py:1732: SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame

What this error actually means

The warning is about ambiguous ownership. A slice such as `df[df.status == "open"]` may share blocks with `df`, or may already be an independent object; pandas cannot promise which after dtype and layout changes. Assigning through that slice therefore has no defined target.

It is a correctness warning, not a performance warning. In one version the parent appears changed, in another it does not, and a later operation may consolidate blocks and change the result again. Silencing the warning globally preserves the ambiguity.

The reliable rule is to select and assign in one operation on the intended owner, or make ownership explicit with `copy()`.

Causes, most common first

  1. 1Chained indexing. The first `[]` produces an intermediate object and the second assignment cannot identify the parent safely.
  2. 2A slice escapes its creating function. A helper returns a view-like subset and another function mutates it, making ownership invisible at the call site.
  3. 3Implicit dtype or block changes. Mixed columns and consolidation alter whether a slice shares storage.

When you see it

  • A filtered report sometimes includes the old value
  • The warning appears only for some column dtypes
  • Tests pass on one pandas version and fail after an upgrade
  • A chained expression such as `df[a][b] = value` appears to run without raising

How to diagnose it

Step 1

Use a deliberate copy test

Compare the parent before and after a write to establish whether the current code relies on view behaviour.

before = df['price'].copy()
subset = df[df['status'].eq('open')]
subset.loc[:, 'price'] = 0
print(df['price'].equals(before))

Step 2

Find chained assignments

Search source rather than suppressing the warning. The pattern is usually visible in a second index operation.

rg -n "\][[]|loc[[^]]+\][[]|iloc[[^]]+\][[]" pipeline/

Step 3

Turn warnings into failures in CI

A warning-as-error policy catches new ambiguous writes while the offending line still has context.

python -W error::pandas.errors.SettingWithCopyWarning -m pytest

The fix

Write through the owner with `.loc[mask, column] = value`.

If a helper owns a subset, return `df.loc[mask].copy()` and document that it is independent.

Use `.assign()` for functional pipelines and return the new frame explicitly.

Do not use `inplace=True` on an intermediate selection; it is the same ownership problem.

Add a regression test that asserts both the transformed subset and the untouched rows.

mask = df['status'].eq('open')
df.loc[mask, 'price'] = 0

# Independent object by contract
open_rows = df.loc[mask].copy()
open_rows['price'] = 0

How to stop it coming back

  • Ban chained assignment in review and lint checks
  • Keep ownership explicit at function boundaries
  • Run tests against the supported pandas range
  • Use warning-as-error in CI
  • Prefer immutable pipeline steps where practical

Practise production debugging in a real repository

Reading about a failure and reproducing one are different skills. Gronex ships broken backend repositories with failing test suites that encode the real invariant, so you debug from evidence instead of memorising symptoms.

FAQ

Can I use mode.chained_assignment = None?

You can, but it converts an uncertainty into silent data corruption. Fix the target of the assignment instead.

Is every slice a copy?

No. The internal representation decides, and that representation can change after operations or versions.

Does copy(deep=True) copy nested Python objects?

It copies array storage, but object elements may still reference mutable Python values. Copy those values separately if they are mutated.

Related

Other errors engineers hit next to this one

Full error and symptom index →