Description
Initial Checks
- I confirm that I'm using Pydantic V2
Description
When Pydantic matches against a union type (in the default smart mode), adding a WrapValidator seems to change its preferred union member type.
Validating a field with a union of two similar models (see code below) without WrapValidator will use the leftmost union member. However, adding a "dummy" WrapValidator causes Pydantic to choose the right union member instead.
Using other validators like AfterValidator doesn't seem to show this issue.
Example Code
from typing import Annotated, Literal
from pydantic import BaseModel, Field, WrapValidator
class ObjectPayload(BaseModel):
name: str
class AddMutation(BaseModel):
type: Literal["add"] = Field("add")
# passes if you replace WrapValidator with AfterValidator or remove it
payload: Annotated[ObjectPayload, WrapValidator(lambda v, nxt: nxt(v))] = Field()
class UpdateMutation(BaseModel):
type: Literal["update"] = Field("update")
payload: ObjectPayload = Field()
class ObjectUpdate(BaseModel):
# passes if you use Field(union_mode="left_to_right")
mutation: AddMutation | UpdateMutation = Field()
def test_union():
obj = ObjectUpdate.model_validate(
{
"mutation": {
"type": "add",
"payload": {"name": "John Doe"},
}
}
)
assert obj.mutation.type == "add"
assert obj.mutation.payload.name == "John Doe"
obj = ObjectUpdate.model_validate(
{
"mutation": {
"type": "update",
"payload": {"name": "John Doe"},
}
}
)
assert obj.mutation.type == "update"
assert obj.mutation.payload.name == "John Doe"
obj = ObjectUpdate.model_validate(
{
"mutation": {
"payload": {"name": "John Doe"},
}
}
)
assert obj.mutation.type == "add"
assert obj.mutation.payload.name == "John Doe"
Python, Pydantic & OS Version
pydantic version: 2.11.2
pydantic-core version: 2.33.1
pydantic-core build: profile=release pgo=false
install path: /Users/chiawei.ong/dev/pL/product-api/.direnv/python-3.12.10/lib/python3.12/site-packages/pydantic
python version: 3.12.10 (main, Apr 8 2025, 11:35:47) [Clang 16.0.0 (clang-1600.0.26.6)]
platform: macOS-15.4-arm64-arm-64bit
related packages: mypy-1.15.0 pydantic-extra-types-2.10.3 typing_extensions-4.13.1
commit: unknown