Back to Blog
Python

Python Pydantic ConfigDict Extra Fields and Strict Mode

python pydantic configdict extra fields and strict mode: Understand how Pydantic ConfigDict's extra field policy and strict mode work together in Python to control val...

PydanticConfigDictExtra FieldsStrict ModeValidation
Illustration of Pydantic ConfigDict controlling extra fields and strict mode in Python models

When working with Pydantic in Python, controlling how models handle unexpected input is a core part of building robust validation. The ConfigDict class, introduced in Pydantic v2, centralizes configuration options, and two of the most frequently misunderstood settings are extra and strict. Understanding how python pydantic configdict extra fields and strict mode interact determines whether your API rejects unknown fields, silently drops them, or accepts them without complaint.

What ConfigDict Controls in Pydantic

ConfigDict is a type alias for a dictionary that you pass to a model's model_config attribute. It replaces the older Config class from Pydantic v1. The settings you define here affect validation, serialization, and overall model behavior. Two options stand out for input handling: extra and strict. The extra option defines what happens when the input contains keys that are not declared as fields. The strict option changes how strictly the field types are validated, and it also influences how extra fields are treated.

The extra Policy: allow, forbid, ignore

The extra setting accepts three string values:

  • ignore (default): Extra keys are silently ignored and not stored on the model instance.
  • allow: Extra keys are stored as attributes on the model, accessible via model_extra.
  • forbid: Extra keys raise a ValidationError.

Here is a minimal example:

from pydantic import BaseModel, ConfigDict class IgnoreModel(BaseModel): model_config = ConfigDict(extra="ignore") name: str class AllowModel(BaseModel): model_config = ConfigDict(extra="allow") name: str class ForbidModel(BaseModel): model_config = ConfigDict(extra="forbid") name: str data = {"name": "Ada", "age": 37} print(IgnoreModel(**data)) # name='Ada' print(AllowModel(**data).model_extra) # {'age': 37} # ForbidModel(**data) raises ValidationError

The choice of policy depends on whether you want to be strict about the shape of incoming data. For APIs that consume external payloads, forbid catches typos and unexpected fields early. For internal tools where forward compatibility matters, ignore can prevent breaking changes when the producer adds fields.

Strict Mode and Its Effect on Extra Fields

Strict mode is a separate configuration that controls type coercion. When strict=True, Pydantic does not coerce values from one type to another; a string "123" will not be accepted for an int field, for example. Strict mode also changes how extra fields are handled in one important way: when extra="allow" and strict=True, the extra values are stored exactly as they were passed, without any type coercion. In non-strict mode, extra values are still validated and coerced according to the field's type if the field is defined, but for extra fields there is no declared type, so they are simply stored as-is.

The interaction becomes more visible when you combine strict with extra="forbid". Strict mode does not alter the behavior of forbid; it still raises an error on any unexpected key. The real difference appears when you use allow and want to preserve the raw input types.

Combining extra and strict: Realistic Scenarios

Consider an API that receives a JSON payload with a known set of fields plus a dynamic set of additional metadata. You want to accept the metadata but avoid any type coercion on it. Setting extra="allow" and strict=True gives you that behavior.

from pydantic import BaseModel, ConfigDict class Event(BaseModel): model_config = ConfigDict(extra="allow", strict=True) name: str timestamp: int payload = {"name": "deploy", "timestamp": "1700000000", "meta": {"env": "prod"}} event = Event(**payload) print(event.timestamp) # "1700000000" - string, not int, because strict=True print(event.model_extra) # {'meta': {'env': 'prod'}}

In this example, timestamp is declared as int, but strict mode prevents the string from being coerced, so validation fails. If you intended to accept a string timestamp, you would need to declare it as str. The extra field meta is stored as a dictionary without any coercion.

On the other hand, if you need to enforce a strict schema for a public API, you might set extra="forbid" and strict=True to reject both unknown fields and type mismatches. This combination gives you the strongest guarantee that the data matches your contract.

Validation Errors and Debugging

When extra="forbid" is set, a ValidationError is raised with a message that includes the unexpected key. The error location points to the field that caused the problem. For example:

try: ForbidModel(**{"name": "Ada", "age": 37}) except ValidationError as e: print(e)

The error output will contain something like Extra inputs are not permitted. This is helpful during development because it immediately surfaces typos in client code or changes in the data contract.

Strict mode errors are different. They occur when a value's type does not match the declared type, and the error message indicates the expected type versus the received type. When both strict and forbid are active, you may see multiple errors in the same exception, which can make debugging more complex. Using model_dump() on the model instance can help you inspect what was actually stored when extra="allow" is used.

Performance and Maintainability Considerations

The extra policy has a small runtime cost. With ignore, Pydantic still iterates over the input keys to check for extras, so it is not free. With allow, the extra fields are stored in an internal dictionary, which adds a small memory overhead. With forbid, the validation process has to check each key against the set of declared fields, which is similar to ignore in cost. In practice, these differences are negligible for typical API workloads, but they can add up in high-throughput data pipelines that process millions of records.

Maintainability is a more important factor. Using extra="allow" can hide mistakes in your data contracts, because unknown fields are silently accepted. This makes it harder to detect when upstream systems change their payloads. extra="forbid" makes the contract explicit and fails fast, which is often preferable in production services. ignore is a middle ground that allows forward compatibility without storing unexpected data.

Choosing the Right Configuration for Your API

The right combination of extra and strict depends on the role of the model. For request validation in a public API, extra="forbid" and strict=False is a common default because it rejects unknown fields while still allowing reasonable type coercion like string-to-int conversion. For internal service-to-service communication where both sides are controlled, extra="forbid" with strict=True gives the strongest contract enforcement. For models that need to accept evolving payloads, such as webhook receivers, extra="ignore" or extra="allow" with strict=False provides flexibility.

When you choose extra="allow", remember that the extra fields are not typed. They are stored as Any and will not be validated. If you need to validate those fields, you should define them explicitly in the model. Similarly, strict mode should be used deliberately because it disables coercion that may be expected by other parts of your system. Test your configuration with representative payloads to ensure it behaves as intended.

python pydantic configdict extra fields and strict mode: Pra | RYUSLOG DEV