Skip to content

UserWarning: Pydantic serializer warnings >= v2.11.0 #11747

@stdkoehler

Description

@stdkoehler

Initial Checks

  • I confirm that I'm using Pydantic V2

Description

For all pydantic versions >= 2.11.0 I receive the following warning for the code posted below.

  • For pydantic 2.10.6 the warning doesn't occur.
  • The serializing seems to works correctly.
  • The warning itself is confusing, as it says it expects AStageSeries[float] and also tells us that it got input_type=AStageSeries[float]
UserWarning: Pydantic serializer warnings:
  PydanticSerializationUnexpectedValue(Expected `AStageSeries[float]` - serialized value may not be as expected [input_value=AStageSeries[float](stage....0, 2.1], a2=[3.0, 3.1]), input_type=AStageSeries[float]])
  PydanticSerializationUnexpectedValue(Expected `BStageSeries[float]` - serialized value may not be as expected [input_value=AStageSeries[float](stage....0, 2.1], a2=[3.0, 3.1]), input_type=AStageSeries[float]])
  return self.__pydantic_serializer__.to_json(

Example Code

from enum import Enum
from typing import Literal, TypeVar, Generic, Annotated
from pydantic import BaseModel, Field

T = TypeVar("T", bound=float | str)

class StageData(BaseModel, Generic[T]):
    stage_no: int = Field(...)
    base: T = Field(...)

class AStageData(StageData[T], BaseModel, Generic[T]):
    type: Literal["A"] = Field(
        ...
    )
    a1: T = Field(...)
    a2: T = Field(...)

class BStageData(StageData[T], BaseModel, Generic[T]):
    type: Literal["B"] = Field(
        ...
    )
    b1: T = Field(...)
    b2: T = Field(...)

type StageDataBase[T] = Annotated[
    AStageData[T] | BStageData[T], Field(discriminator="type")
]


class StageSeries(BaseModel, Generic[T]):
    stage_no: int = Field(...)
    base: list[T] = Field(
        []
    )

    def append_value(self, stage_data: StageDataBase[T]) -> None:
        self.base.append(stage_data.base)

class AStageSeries(StageSeries[T], Generic[T]):
    type: Literal["A"] = Field(
        ...
    )
    a1: list[T] = Field(
        []
    )
    a2: list[T] = Field(
        []
    )

    def append_value(self, stage_data: AStageData[T]) -> None:
        super().append_value(stage_data)
        self.a1.append(stage_data.a1)
        self.a2.append(stage_data.a2)

class BStageSeries(StageSeries[T], Generic[T]):
    type: Literal["B"] = Field(
        ...
    )
    b1: list[T] = Field(
        []
    )
    b2: list[T] = Field(
        []
    )

    def append_value(self, stage_data: BStageData[T]) -> None:
        super().append_value(stage_data)
        self.b1.append(stage_data.b1)
        self.b2.append(stage_data.b2)

type StageSeriesBase[T] = Annotated[
    AStageSeries[T] | BStageSeries[T], Field(discriminator="type")
]

class Series(BaseModel, Generic[T]):
    stages: list[StageSeriesBase[T]] = Field(
        []
    )

    def append_value(self, stages: list[StageDataBase[T]]) -> None:
        for stage_data in stages:
            stage = self.get_stage(stage_data)
            stage.append_value(stage_data)

    def get_stage(self, stage_data: StageDataBase[T]) -> StageSeriesBase[T]:
        # this throws "Parameterized generics cannot be used with class or instance checks"
        # but this is the only possible way to instantiate the correct generic type class
        # google didn't provide any meaningful info to that mypy error either
        try:
            stage = next(s for s in self.stages if s.stage_no == stage_data.stage_no)
        except StopIteration:
            if isinstance(stage_data, AStageData[float]):
                stage = AStageSeries[float](
                    type="A", stage_no=stage_data.stage_no
                )
            elif isinstance(stage_data, AStageData[str]):
                stage = AStageSeries[str](
                    type="A", stage_no=stage_data.stage_no
                )
            elif isinstance(trend_stage, BStageData[float]):
                stage = BStageSeries[float](
                    type="B", stage_no=stage_data.stage_no
                )
            elif isinstance(trend_stage, BStageData[std]):
                stage = BlStageSeries[str](
                    type="B", stage_no=stage_data.stage_no
                )
            else:
                raise ValueError(f"Unsupported type: {type(stage_data)}") from None

            self.stages.append(stage)
        return stage

g = Series[float]()
g.append_value(
    stages = [
        AStageData[float](
            type="A",
            stage_no=1,
            base=1,
            a1=2,
            a2=3,
        )
    ]
)
g.append_value(
    stages = [
        AStageData[float](
            type="A",
            stage_no=1,
            base=1.1,
            a1=2.1,
            a2=3.1,
        )
    ]
)

g.model_dump_json()

Python, Pydantic & OS Version

             pydantic version: 2.11.3
        pydantic-core version: 2.33.1
          pydantic-core build: profile=release pgo=false
                 install path: C:\Users\DEKOEHLS\AppData\Local\miniconda3\envs\jupyter-313\Lib\site-packages\pydantic
               python version: 3.13.3 | packaged by conda-forge | (main, Apr 10 2025, 22:12:50) [MSC v.1943 64 bit (AMD64)]
                     platform: Windows-10-10.0.19045-SP0
             related packages: typing_extensions-4.13.2
                       commit: unknown

Metadata

Metadata

Assignees

Labels

bug V2Bug related to Pydantic V2

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions