Skip to content

no-invalid-pydantic-bypass

Do not create a provably invalid model through Pydantic validation bypass APIs.

Why

model_construct and model_copy(update=...) store supplied values without validation. A contradictory literal or an omitted required construction field can therefore invalidate a model's declared type while the permissive bypass signatures still pass static checking.

Fix

Supply values satisfying the model contract and every required field, or validate a complete input mapping with the normal constructor or model_validate. A model_validate call on an existing model instance does not necessarily revalidate it; keep trusted bypasses only when their inputs preserve the contract.

Examples

Before — flagged Unchecked list elements must satisfy the stored field type
app/models.py
from pydantic import BaseModel
class Payload(BaseModel):
labels: list[str]
payload = Payload.model_construct(labels=[3])
After — preferred Trusted list elements preserve the field contract
app/models.py
from pydantic import BaseModel
class Payload(BaseModel):
labels: list[str]
payload = Payload.model_construct(labels=["ready"])
Before — flagged Unchecked construction stores a tag outside the declared vocabulary
app/models.py
from typing import Literal
from pydantic import BaseModel
class Job(BaseModel):
kind: Literal["queued", "done"]
job = Job.model_construct(kind="unknown")
After — preferred Trusted construction still satisfies the declared vocabulary
app/models.py
from typing import Literal
from pydantic import BaseModel
class Job(BaseModel):
kind: Literal["queued", "done"]
job = Job.model_construct(kind="queued")