FastAPI 422 Unprocessable Entity: What It Means and How to Fix It

A 422 from FastAPI is not a bug in your server — it's FastAPI telling you the request body or query didn't match your Pydantic model. The response JSON tells you exactly which field. Here's how to read it.

BytExplorer 6 min read July 18, 2026

You call your endpoint and FastAPI hands back a 422:

{
  "detail": [
    {
      "type": "missing",
      "loc": ["body", "email"],
      "msg": "Field required",
      "input": {"name": "Ada"}
    }
  ]
}

422 Unprocessable Entity means your request reached the endpoint fine, but the data failed validation against the Pydantic model. FastAPI rejects it before your function ever runs — so the fix is never inside your handler. It's in the mismatch between what you sent and what the model requires. The good news: the detail array names the exact problem.

Step 1: Read the loc and msg — they point straight at the field

Every item in detail has a loc (location) and a msg. Read loc right to left:

  • ["body", "email"] + "Field required" — you didn't send email in the JSON body.
  • ["query", "limit"] + "Input should be a valid integer"?limit=abc isn't a number.
  • ["body", "age"] + "Input should be greater than 0" — a constraint (gt=0) failed.
  • ["path", "item_id"] — the value in the URL path is the wrong type.

The first element of loc tells you where to look (body, query, path, header); the rest names the field.

Cause: you sent form data but the model expects JSON (or vice-versa)

This is the most common surprise. A plain Pydantic body model expects a JSON request:

curl -X POST /users -H "Content-Type: application/json" -d '{"name":"Ada","email":"[email protected]"}'

If you send -d name=Ada without the JSON header, FastAPI can't parse it into the model and you get 422. If you actually want form fields, you have to declare them with Form(...), not a Pydantic body model.

Cause: a required field is missing or misspelled

class User(BaseModel):
    name: str
    email: str          # required — no default

@app.post("/users")
def create(user: User): ...

Send {"name": "Ada"} and email triggers "Field required". Either send the field, or make it optional with a default:

email: str | None = None

Cause: the type doesn't match

age: int will reject "age": "twenty". Pydantic will coerce "25"25, but it won't invent an integer from a word. Match the client's real payload to the model's types, or loosen the type.

The fastest way to debug it

Open /docs (FastAPI's built-in Swagger UI). It shows the exact schema each endpoint expects and lets you send a request that's guaranteed to match — if your hand-built request 422s but the /docs one works, the difference between them is your bug.

The checklist

  1. Read the detail array — loc + msg name the exact field and reason.
  2. First element of loc: body, query, path, or header — that's where to fix it.
  3. Sending JSON? Set Content-Type: application/json and a JSON body.
  4. "Field required" → send it, or give the model field a default.
  5. Type mismatch → align the payload with the model, or relax the type.
  6. Reproduce it in /docs to see the schema FastAPI actually expects.

Frequently Asked Questions

Why does FastAPI return 422 instead of 400?

FastAPI uses 422 Unprocessable Entity specifically for request-validation failures (the syntax was fine, the content didn't satisfy the schema). A 400 is reserved for a genuinely malformed request. You can override the handler if you prefer 400, but 422 is the intended, standards-based default.

Where is the actual error in a 422 response?

In the detail array. Each entry's loc field is the path to the offending value and msg explains what was wrong — read those two first, always.

How do I make a field optional so it stops 422-ing?

Give it a default in the Pydantic model, e.g. email: str | None = None. A field with no default is required, and its absence produces "Field required".

Put it into practice

Stop reading, start building

This pairs with a hands-on BytExplorer course — do it on your own machine and actually keep the skill.

More in Troubleshooting