On this page

Engineering5 min read

Fix FastAPI 422 Unprocessable Entity — 5 Causes and Fixes

FastAPI 422 errors mean your request body doesn't match the Pydantic model. The response tells you exactly which field failed — here's how to read it and fix the 5 most common causes: missing fields, wrong types, nested models, query vs body confusion, and enum mismatches.

fastapipydantic422validationpythonapi

Reading the 422 Response

FastAPI returns 422 Unprocessable Entity when the request body doesn't match the Pydantic model defined in your route. The response body tells you exactly which field failed and why.

json
{
  "detail": [
    {
      "loc": ["body", "email"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

The detail array contains one object per validation failure:

  • loc — path to the field that failed. ["body", "email"] means the email field in the request body. ["body", "user", "age"] means nested: request body → user object → age field.
  • msg — human-readable reason
  • type — machine-readable error code

Read loc first. That tells you which field. msg tells you what's wrong with it.

Cause 1: Missing Required Field

python
class UserCreate(BaseModel):
    email: str
    password: str
    name: str  # required — no default value

Sending a body without name:

json
{ "email": "user@example.com", "password": "secret" }

Returns 422: field required for name.

Fix: Either send the field, or make it optional in the model.

python
from typing import Optional

class UserCreate(BaseModel):
    email: str
    password: str
    name: Optional[str] = None  # optional — 422 won't fire if missing

Cause 2: Wrong Type

python
class Item(BaseModel):
    quantity: int
    price: float

Sending:

json
{ "quantity": "five", "price": 9.99 }

Returns 422: value is not a valid integer for quantity.

Note: FastAPI does try to coerce types automatically. Sending "5" for an int field will work — FastAPI converts the string to 5. But "five" can't be coerced to an integer, so it fails.

Fix: Send the correct type in your request. If your client always sends strings, use a validator to coerce.

python
from pydantic import validator

class Item(BaseModel):
    quantity: int
    price: float

    @validator('quantity', pre=True)
    def parse_quantity(cls, v):
        return int(v)  # coerce any string to int before validation

Cause 3: Nested Model Mismatch

python
class Address(BaseModel):
    street: str
    city: str
    zip_code: str

class User(BaseModel):
    email: str
    address: Address

Sending flat body instead of nested:

json
{ "email": "user@example.com", "street": "123 Main St" }

Returns 422: address field required.

Fix: Send the nested structure.

json
{
  "email": "user@example.com",
  "address": {
    "street": "123 Main St",
    "city": "Portland",
    "zip_code": "97201"
  }
}

Cause 4: Query Param vs Body Confusion

FastAPI distinguishes between path params, query params, and body. A common mistake:

python
@app.post("/users")
async def create_user(email: str, password: str):  # ← these are query params, not body
    ...

Sending a JSON body with email and password → 422 because FastAPI expects them as query strings (/users?email=...&password=...), not in the body.

Fix: Use a Pydantic model for body parameters.

python
class UserCreate(BaseModel):
    email: str
    password: str

@app.post("/users")
async def create_user(user: UserCreate):  # ← body param
    ...

Cause 5: Enum Value Not in Allowed List

python
from enum import Enum

class Role(str, Enum):
    admin = "admin"
    user = "user"
    viewer = "viewer"

class UserCreate(BaseModel):
    role: Role

Sending "superadmin" → 422: value is not a valid enumeration member.

Fix: Send one of the allowed values. Check your Enum definition for valid options.

Debug 422 Locally

python
# Add this to your FastAPI app during development
from fastapi import Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    print(f"422 on {request.url}")
    print(f"Body: {await request.body()}")
    print(f"Errors: {exc.errors()}")
    return JSONResponse(status_code=422, content={"detail": exc.errors()})

This logs the full incoming body alongside the validation errors — lets you see exactly what was sent vs what was expected.


For 422 errors in complex nested models or when validation logic spans multiple validators, paste the model definition and the request body into DebugAI. It identifies which field failed validation and why, including non-obvious coercion failures.

Debug faster starting today.

Free VS Code extension. 10 sessions/day. No credit card.

Install Free →

Related Posts

Engineering

Fix Express CORS Error — No 'Access-Control-Allow-Origin' Header

6 min read

Engineering

Fix Django IntegrityError — UNIQUE, NOT NULL, and Foreign Key Violations

5 min read

← All posts