This is an issue when a Pydantic model field uses Optional[Type] or Type | None type hints without providing an explicit default value, or when using Field(…​) with the ellipsis operator.

Why is this an issue?

In Pydantic models, there is a common misconception about what Optional[Type] means. Many developers assume that marking a field as Optional[Type] makes it optional during validation, but this is not the case.

The Optional[Type] type hint only indicates that a field can accept either a value of Type or None. It does not affect whether the field is required during validation. Without an explicit default value, Pydantic will still raise a validation error if the field is missing from the input data.

To make a field truly optional (meaning it doesn’t need to be provided during validation), you must assign a default value. This is typically None for optional fields, but can be any appropriate default value.

A particularly problematic pattern is using Field(…​) with Optional[Type]. The ellipsis (…​) is Pydantic’s way of explicitly marking a field as required. This creates a direct contradiction: the type hint says the field can be None, but the Field(…​) says it must be provided. In this case, Pydantic prioritizes the ellipsis, making the field required despite the Optional annotation.

This mismatch between developer intent and actual behavior leads to unexpected validation errors in production, confusing API consumers who receive "field required" errors for fields they reasonably expected to be optional based on the type hints.

What is the potential impact?

When optional fields lack explicit default values, the application will reject valid requests where users omit fields they believe to be optional. This leads to:

How to fix it

Add an explicit default value (typically None) to fields with Optional type hints. This makes the field truly optional during validation while maintaining the type safety that allows None values.

Code examples

Noncompliant code example

from typing import Optional
from pydantic import BaseModel

class TwitterAccount(BaseModel):
    username: str
    followers: int

class UserRead(BaseModel):
    name: str
    twitter_account: Optional[TwitterAccount]  # Noncompliant

Compliant solution

from typing import Optional
from pydantic import BaseModel

class TwitterAccount(BaseModel):
    username: str
    followers: int

class UserRead(BaseModel):
    name: str
    twitter_account: Optional[TwitterAccount] = None

Resources

Documentation