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
@@ -207,16 +207,13 @@ impl GeneralFieldsSerializer {
continue;
}
- if value.is(missing_sentinel) {
- continue;
- }
# /// 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
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
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
- 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
- GitHub issue: #12628
- Fix PR: https://github.com/pydantic/pydantic/pull/12635
- Reproduced locally: No (not executed)
- Last verified: 2026-02-09
- Confidence: 0.80
- Did this fix it?: Yes (upstream fix exists)
- Own content ratio: 0.41
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.”
Failure Signature (Search String)
- warning raised when calling `model_dump` on model with nested `MISSING` fields
Copy-friendly signature
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 Message
-------------
warning raised when calling `model_dump` on model with nested `MISSING` fields
from pydantic.experimental.missing_sentinel import MISSING
Minimal Reproduction
# /// 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.
Fix reference: https://github.com/pydantic/pydantic/pull/12635
Last verified: 2026-02-09. Validate in your environment.
When NOT to Use This Fix
- This fix should not be used if the model's serialization behavior needs to remain unchanged.
Verify Fix
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.