342 words, 2 min read

When working with APIs or configuration files, it’s common to receive raw JSON data that needs to be parsed into structured Pydantic models. However, Pydantic’s model_validate_json() can behave unexpectedly when your data is already a Python list or dictionary.

Let’s take a simple example.

from pydantic import BaseModel, Field

class UserDTO(BaseModel):
    """Model for user information."""

    name: str = Field(..., description="Full name of the user")
    email: str = Field(..., description="Email address of the user")

Suppose you receive this data from an API:

users = [
    {"name": "Alice", "email": "alice@example.com"},
    {"name": "Bob", "email": "bob@example.com"},
]

If you try this:

UserDTO.model_validate_json(users)

it won’t work, because model_validate_json() expects a JSON string, not a Python list or dict.

Option 1: Parsing from Python objects

If your JSON is already parsed into Python objects (for example, using json.loads()), use model_validate() or TypeAdapter.validate_python():

from pydantic import TypeAdapter

# Parse each item individually
models = [UserDTO.model_validate(item) for item in users]

# Or parse the entire list at once
adapter = TypeAdapter(list[UserDTO])
models = adapter.validate_python(users)

Option 2: Parsing directly from JSON

If you have the raw JSON string instead:

json_data = '[{"name": "Alice", "email": "alice@example.com"}]'

you can parse it in one step:

from pydantic import TypeAdapter

adapter = TypeAdapter(list[UserDTO])
models = adapter.validate_json(json_data)

Optional: Using a wrapper model

If you want a cleaner interface, you can define a wrapper model that represents a list of items:

class UserList(BaseModel):
    __root__: list[UserDTO]

Now you can parse JSON directly:

UserList.model_validate_json(json_data)

and get structured, typed models ready for use.

Conclusion

  • Use model_validate() for Python dicts/lists
  • Use model_validate_json() for raw JSON strings
  • Use TypeAdapter or wrapper models for lists of objects