Jump to solution
Verify

The Fix

Fixes the issue where `RootModel.model_copy(deep=False)` did not create a shallow copy of the root value, causing unexpected mutations.

Based on closed pydantic/pydantic issue #12543 · PR/commit linked

Jump to Verify Open PR/Commit
@@ -99,7 +99,9 @@ def __copy__(self) -> Self: cls = type(self) m = cls.__new__(cls) - _object_setattr(m, '__dict__', copy(self.__dict__)) + new_dict = copy(self.__dict__) + new_dict['root'] = copy(self.__dict__['root'])
repro.py
from pydantic import RootModel def main(): list_1 = RootModel[list[int]]([1, 2, 3]) list_2 = list_1.model_copy(deep=False) assert list_1.root is list_2.root
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Apply the official fix\nFixes the issue where `RootModel.model_copy(deep=False)` did not create a shallow copy of the root value, causing unexpected mutations.\nWhen NOT to use: Do not use this fix if a deep copy of the root value is required.\n\n

Why This Fix Works in Production

  • Trigger: assert list_1.root is not list_2.root
  • Mechanism: The `model_copy()` method did not create a shallow copy of the root value, leading to shared references

Why This Breaks in Prod

  • The `model_copy()` method did not create a shallow copy of the root value, leading to shared references
  • Production symptom (often without a traceback): assert list_1.root is not list_2.root

Proof / Evidence

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“Check out the source code of the .model_copy(), if u want a shallow copy, u should use: @davidhewitt could close this”
@yinxiangshi · 2025-11-19 · source
“Thank you @Viicos for explaining my issue better. This is precisely what I mean.”
@keriksson-rosenqvist-oqc · 2025-11-19 · source
“While I don't think this is a bug, the current behavior is debatable”
@Viicos · 2025-11-19 · source
“Thanks, as @yinxiangshi says, .model_copy() supports both shallow and deep copies. By default it is a shallow copy. If you pass deep=True, you get a…”
@davidhewitt · 2025-11-19 · source

Failure Signature (Search String)

  • assert list_1.root is not list_2.root
  • assert list_1.root is list_2.root
Copy-friendly signature
signature.txt
Failure Signature ----------------- assert list_1.root is not list_2.root assert list_1.root is list_2.root

Error Message

Signature-only (no traceback captured)
error.txt
Error Message ------------- assert list_1.root is not list_2.root assert list_1.root is list_2.root

Minimal Reproduction

repro.py
from pydantic import RootModel def main(): list_1 = RootModel[list[int]]([1, 2, 3]) list_2 = list_1.model_copy(deep=False) assert list_1.root is list_2.root

Environment

  • Pydantic: 2

What Broke

Using `model_copy()` resulted in unexpected mutations due to shared root references.

Why It Broke

The `model_copy()` method did not create a shallow copy of the root value, leading to shared references

Fix Options (Details)

Option A — Apply the official fix

Fixes the issue where `RootModel.model_copy(deep=False)` did not create a shallow copy of the root value, causing unexpected mutations.

When NOT to use: Do not use this fix if a deep copy of the root value is required.

Fix reference: https://github.com/pydantic/pydantic/pull/12679

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • Do not use this fix if a deep copy of the root value is required.

Verify Fix

verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.

Did This Fix Work in Your Case?

Quick signal helps us prioritize which fixes to verify and improve.

Prevention

  • Add a CI check that diffs key outputs after upgrades (OpenAPI schema snapshots, JSON payload shapes, CLI output).
  • Upgrade behind a canary and run integration tests against the canary before 100% rollout.

Related Issues

No related fixes found.

Sources

We don’t republish the full GitHub discussion text. Use the links above for context.