Jump to solution
Verify

The Fix

Prevents a serialization warning when the `MISSING` sentinel is present in a nested model by modifying the serializer behavior.

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

Jump to Verify Open PR/Commit
@@ -207,16 +207,13 @@ impl GeneralFieldsSerializer { continue; } - if value.is(missing_sentinel) { - continue; - }
repro.py
# /// script # requires-python = ">=3.11" # dependencies = [ # "pydantic=2.12.5", # ] # /// from pydantic import BaseModel, model_serializer from pydantic.experimental.missing_sentinel import MISSING class TransformBroken(BaseModel): scale: tuple[float, ...] | MISSING = MISSING translation: tuple[float, ...] | MISSING = MISSING # WITH custom serializer - this fixes the warning class TransformFixed(BaseModel): scale: tuple[float, ...] | MISSING = MISSING translation: tuple[float, ...] | MISSING = MISSING # this model_serializer fixes the issue for some reason @model_serializer def serialize_model(self) -> dict[str, tuple[float, ...]]: result: dict[str, tuple[float, ...]] = {} if self.scale is not MISSING: result["scale"] = self.scale if self.translation is not MISSING: result["translation"] = self.translation return result class ScaleLevelBroken(BaseModel): asset: str transform: TransformBroken | MISSING = MISSING class ScaleLevelFixed(BaseModel): asset: str transform: TransformFixed | MISSING = MISSING class MultiscalesBroken(BaseModel): layout: tuple[ScaleLevelBroken, ...] class MultiscalesFixed(BaseModel): layout: tuple[ScaleLevelFixed, ...] data = { "layout": [ { "asset": "0/data", "transform": {"scale": (1.0, 1.0)}, # translation is MISSING }, { "asset": "1/data", "transform": { "scale": (2.0, 2.0), "translation": (0.5, 0.5), }, }, ] } a = MultiscalesBroken(**data).model_dump() """ PydanticSerializationUnexpectedValue(Expected 2 fields but got 1: Expected `TransformBroken` - serialized value may not be as expected [field_name='transform', input_value=TransformBroken(scale=(1...., translation=<MISSING>), input_type=TransformBroken]) PydanticSerializationUnexpectedValue(Expected 'MISSING' sentinel) return self.__pydantic_serializer__.to_python( """ b = MultiscalesFixed(**data).model_dump() assert a == b
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\nPrevents a serialization warning when the `MISSING` sentinel is present in a nested model by modifying the serializer behavior.\nWhen NOT to use: This fix should not be used if the model's serialization behavior needs to remain unchanged.\n\n

Why This Fix Works in Production

  • Trigger: warning raised when calling `model_dump` on model with nested `MISSING` fields
  • Mechanism: The serializer did not handle the MISSING sentinel correctly in nested models
Production impact:
  • If left unfixed, this can cause silent data inconsistencies that propagate (bad cache entries, incorrect downstream decisions).

Why This Breaks in Prod

  • The serializer did not handle the MISSING sentinel correctly in nested models
  • Production symptom (often without a traceback): warning raised when calling `model_dump` on model with nested `MISSING` fields

Proof / Evidence

Discussion

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

“MRE: I think the model_serializer added to TransformFixed has the same output as the default serializer. But overriding the default serializer prevents the warning.”
Issue thread · issue description · source

Failure Signature (Search String)

  • warning raised when calling `model_dump` on model with nested `MISSING` fields
Copy-friendly signature
signature.txt
Failure Signature ----------------- warning raised when calling `model_dump` on model with nested `MISSING` fields from pydantic.experimental.missing_sentinel import MISSING

Error Message

Signature-only (no traceback captured)
error.txt
Error Message ------------- warning raised when calling `model_dump` on model with nested `MISSING` fields from pydantic.experimental.missing_sentinel import MISSING

Minimal Reproduction

repro.py
# /// script # requires-python = ">=3.11" # dependencies = [ # "pydantic=2.12.5", # ] # /// from pydantic import BaseModel, model_serializer from pydantic.experimental.missing_sentinel import MISSING class TransformBroken(BaseModel): scale: tuple[float, ...] | MISSING = MISSING translation: tuple[float, ...] | MISSING = MISSING # WITH custom serializer - this fixes the warning class TransformFixed(BaseModel): scale: tuple[float, ...] | MISSING = MISSING translation: tuple[float, ...] | MISSING = MISSING # this model_serializer fixes the issue for some reason @model_serializer def serialize_model(self) -> dict[str, tuple[float, ...]]: result: dict[str, tuple[float, ...]] = {} if self.scale is not MISSING: result["scale"] = self.scale if self.translation is not MISSING: result["translation"] = self.translation return result class ScaleLevelBroken(BaseModel): asset: str transform: TransformBroken | MISSING = MISSING class ScaleLevelFixed(BaseModel): asset: str transform: TransformFixed | MISSING = MISSING class MultiscalesBroken(BaseModel): layout: tuple[ScaleLevelBroken, ...] class MultiscalesFixed(BaseModel): layout: tuple[ScaleLevelFixed, ...] data = { "layout": [ { "asset": "0/data", "transform": {"scale": (1.0, 1.0)}, # translation is MISSING }, { "asset": "1/data", "transform": { "scale": (2.0, 2.0), "translation": (0.5, 0.5), }, }, ] } a = MultiscalesBroken(**data).model_dump() """ PydanticSerializationUnexpectedValue(Expected 2 fields but got 1: Expected `TransformBroken` - serialized value may not be as expected [field_name='transform', input_value=TransformBroken(scale=(1...., translation=<MISSING>), input_type=TransformBroken]) PydanticSerializationUnexpectedValue(Expected 'MISSING' sentinel) return self.__pydantic_serializer__.to_python( """ b = MultiscalesFixed(**data).model_dump() assert a == b

What Broke

Warnings were raised during serialization of models with nested MISSING fields.

Why It Broke

The serializer did not handle the MISSING sentinel correctly in nested models

Fix Options (Details)

Option A — Apply the official fix

Prevents a serialization warning when the `MISSING` sentinel is present in a nested model by modifying the serializer behavior.

When NOT to use: This fix should not be used if the model's serialization behavior needs to remain unchanged.

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

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

  • This fix should not be used if the model's serialization behavior needs to remain unchanged.

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.