Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pydantic Settings cannot deserialize JSON value of type declared with PEP-695 style type alias #536

Open
palle-k opened this issue Feb 11, 2025 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@palle-k
Copy link

palle-k commented Feb 11, 2025

With the following Pydantic settings model

from typing import Annotated, Literal
from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings

class Bar(BaseModel):
    type: Literal["bar"] = "bar"
    bar: int
    
class Baz(BaseModel):
    type: Literal["baz"] = "baz"
    baz: str
    
type BarOrBaz = Annotated[Bar | Baz, Field(discriminator="type")]

class Foo(BaseSettings):
    foo: BarOrBaz

and the env

export FOO='{"type": "bar", "bar": 42}'

Pydantic Settings fails to deserialize FOO:

Foo()
ValidationError: 1 validation error for Foo
foo
  Input should be a valid dictionary or object to extract fields from [type=model_attributes_type, input_value='{"type": "bar", "bar": 42}', input_type=str]
    For further information visit https://errors.pydantic.dev/2.10/v/model_attributes_type

Declaring BarOrBaz without the PEP-695 style type alias (i.e. leaving out the type keyword) works as expected - validation succeeds.

Version Info

             pydantic version: 2.10.6
        pydantic-core version: 2.27.2
          pydantic-core build: profile=release pgo=false
                 install path: /path/to/my/venv/lib/python3.13/site-packages/pydantic
               python version: 3.13.1 (main, Dec  3 2024, 17:59:52) [Clang 19.1.5 ]
                     platform: macOS-15.3-arm64-arm-64bit-Mach-O
             related packages: mypy-1.15.0 fastapi-0.115.8 pydantic-settings-2.7.1 typing_extensions-4.12.2
                       commit: unknown
@hramezani
Copy link
Member

Thanks @palle-k for reporting this bug. pydantic-settings considers foo as a normal field(not complex). So, it doesn't decode it.

Meanwhile, you can use field_serializer to decode the value manually:

import json

from typing import Annotated, Literal
from pydantic import BaseModel, Field, field_validator
from pydantic_settings import BaseSettings

class Bar(BaseModel):
    type: Literal["bar"] = "bar"
    bar: int
    
class Baz(BaseModel):
    type: Literal["baz"] = "baz"
    baz: str
    
type BarOrBaz = Annotated[Bar | Baz, Field(discriminator="type")]

class Foo(BaseSettings):
    foo: BarOrBaz

    @field_validator('foo', mode='before')
    @classmethod
    def decode_foo(cls, v: str) -> dict:
        return json.loads(v)

@hramezani hramezani added bug Something isn't working and removed unconfirmed labels Feb 12, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants