422 Unprocessable Entity: {"detail":[{"type":"missing","loc":["body","email"],"msg":"Field required"}]}
Python · updated 2026-11-03
Returned by FastAPI itself, before your endpoint function runs, when request validation fails. Your code never sees the request, so nothing in your handler logs it unless you add a handler for RequestValidationError.
HTTP/1.1 422 Unprocessable Entity
content-type: application/json
{
"detail": [
{
"type": "missing",
"loc": ["body", "email"],
"msg": "Field required",
"input": {"name": "Ada"}
}
]
}Quick fix
Read loc in the response: the first item says where FastAPI looked (body, query, path, header), the rest is the field. Then make the client send that field in that place with the right type, or change the model if the field should be optional.
- Read detail[].loc and detail[].msg in the 422 response.
- If loc starts with "query" but you sent JSON, the parameter is declared as a plain argument: use a Pydantic model or Body() for JSON.
- If the field is optional, give it a default: email: str | None = None.
- Check the client sends Content-Type: application/json with a JSON body, not form data.
- Log validation failures with a RequestValidationError handler so they show up in your error tracker.
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModel
app = FastAPI()
class Signup(BaseModel):
name: str
email: str | None = None # optional fields need a default
@app.post("/signup")
async def signup(body: Signup): # a model = read from the JSON body
return {"ok": True}
@app.exception_handler(RequestValidationError)
async def log_422(request: Request, exc: RequestValidationError):
log.warning("422 on %s: %s", request.url.path, exc.errors())
return JSONResponse(status_code=422, content={"detail": exc.errors()})Why it happens
A JSON field read as a query parameter
A plain function argument like def create(email: str) is a query parameter. Sending it in a JSON body leaves the query empty, so FastAPI reports loc ["query", "email"] as missing.
Optional fields without a default
In Pydantic v2, a field typed str | None is still required unless it has a default. Clients that omit it get "Field required".
Form data or the wrong content type
An HTML form or a client sending application/x-www-form-urlencoded to an endpoint that expects a JSON model fails validation on every field.
Type mismatches
A string where an int is declared, a date in the wrong format, or an enum value that isn't in the list returns a 422 with the expected type in msg.
Other fixes
- Open /docs on your app to see exactly where each parameter is expected (query, body, path).
- For form posts, declare Form() parameters and install python-multipart.
- Validation errors are client mistakes, so they are not exceptions in your code: log them deliberately if you want to see them.
Same error, other wording
- {"detail":[{"type":"int_parsing","loc":["query","page"],"msg":"Input should be a valid integer, unable to parse string as an integer"}]}
- {"detail":[{"type":"json_invalid","loc":["body",0],"msg":"JSON decode error"}]}
- {"detail":[{"type":"missing","loc":["query","item_id"],"msg":"Field required"}]}
Let your coding agent catch the next one
Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:
> Find the 422 responses from our FastAPI app, group them by endpoint and the field in loc, and fix either the client calls or the models so the fields match.
Related errors
- json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
- KeyError: 'email'
- ValueError: invalid literal for int() with base 10: ''
References: FastAPI docs: handling errors (RequestValidationError), FastAPI docs: request body