HTTP 422 Unprocessable Content
422 sits between malformed and accepted: the JSON parsed and has the right content type, but the values don't make sense, such as a negative quantity, an end date before the start date, or an email without an @.
422 Unprocessable Content
The server understands the content type and syntax of the request, but can't process the instructions it contains.
Who fixes it: Client. The request data has to change. The server's job is to say exactly which fields are wrong.
What 422 means
It started as a WebDAV code (RFC 4918, Unprocessable Entity) and was adopted into the core HTTP spec in RFC 9110 as Unprocessable Content. Frameworks use both names.
The value of 422 over a plain 400 is the contract it gives clients: your request was well-formed, so fix the data, not the code. Pair it with a body that lists every invalid field.
Source: RFC 9110 §15.5.21.
Where 422s come from
- FastAPI returns 422 automatically when a request doesn't match its Pydantic model: wrong types, missing fields, or a value sent in the body when the parameter is declared as a query parameter. The
detailarray gives the location (body,query,path) and field of each error. - Rails scaffolded controllers return 422 (
:unprocessable_entity, called:unprocessable_contentsince Rack 3.1) whensavefails validation. Rails also responds 422 to a failed CSRF authenticity token check by default. - Laravel returns 422 with an
errorsobject when validation fails on a JSON request. - Business rules: booking a date in the past, applying an expired coupon.
- The right shape with the wrong types:
"qty": "2"instead of2, or dates not in ISO 8601 format.
How to debug and return a 422
Read the error body
Validation frameworks tell you exactly which field failed. Here is a FastAPI response, trimmed:
curl -s https://api.example.com/items \
-H 'Content-Type: application/json' \
-d '{"name": "", "qty": -1}' | jq
{
"detail": [
{ "type": "string_too_short", "loc": ["body", "name"],
"msg": "String should have at least 1 character" },
{ "type": "greater_than", "loc": ["body", "qty"],
"msg": "Input should be greater than 0" }
]
}Next.js Route Handler: 400 for bad JSON, 422 for bad values
Parse first, then validate. This example uses Zod, but any schema library works the same way.
// app/api/items/route.ts
import { z } from 'zod';
const Item = z.object({
name: z.string().min(1),
qty: z.number().int().positive(),
});
export async function POST(request: Request) {
let body: unknown;
try {
body = await request.json();
} catch {
return Response.json({ error: 'invalid_json' }, { status: 400 });
}
const parsed = Item.safeParse(body);
if (!parsed.success) {
return Response.json(
{ error: 'validation_failed', issues: parsed.error.issues },
{ status: 422 }
);
}
const item = await createItem(parsed.data);
return Response.json(item, { status: 201 });
}Client: show errors next to the fields
Map each error's path (loc in FastAPI, path in Zod, keys of errors in Laravel) to the form input it belongs to. Don't retry automatically; the same data fails the same way.
Headers that matter with 422
- Content-Type: application/problem+json
- RFC 9457 allows extension members, so a problem-details body can carry an
errorsarray with one entry per field.
422 vs similar status codes
- 400 Bad Request: The request couldn't be parsed at all, e.g. broken JSON or a missing Content-Type.
- 409 Conflict: The data is valid but clashes with what's stored, such as a duplicate email or a stale version.
- 415 Unsupported Media Type: The server doesn't accept that
Content-Typeat all, e.g. XML sent to a JSON-only API.
Related status codes
400Bad Request
The server can't or won't process the request because of something it considers a client error.
409Conflict
The request conflicts with the current state of the target resource.
201Created
The request succeeded and created one or more new resources.
413Content Too Large
The request content is larger than the server is willing or able to process.
Looking for another code? Search the full HTTP status codes list, or read which code your API should return in the REST API status codes guide.
Learn more
HTTP Status Codes for REST APIs: 200 vs 201 vs 204, 400 vs 422 vs 429
A practical guide to choosing the right HTTP status code in REST API design. Covers the most confusing pairs: 200 vs 201, 400 vs 422, 401 vs 403, and when to use 503 vs 429.
REST API Design Best Practices: A Practical Guide
The conventions that make REST APIs intuitive and consistent. Covers URL design, HTTP methods, status codes, versioning, pagination, and error responses.
CORS Explained: Why It Happens and How to Fix It
CORS errors happen when a browser blocks a request to a different origin. Learn how the Same-Origin Policy works, what preflight requests are, and how to configure CORS correctly in Express, FastAPI, and Nginx.
Frequently Asked Questions
What is the difference between 400 and 422?▾
400 Bad Request means the server couldn't parse or accept the request as sent: broken JSON, invalid framing, a bad header. 422 means it parsed fine but the content failed validation. Using both lets clients tell programming errors from user-input errors.
Why does FastAPI return 422?▾
FastAPI validates every request against your type hints and Pydantic models and returns 422 with a detail list when anything doesn't match. Common causes are sending a value in the JSON body for a parameter FastAPI expects in the query string, missing required fields, or a string where an int is declared. Each entry's loc shows which field failed.
Is it Unprocessable Entity or Unprocessable Content?▾
Both refer to 422. WebDAV's RFC 4918 called it Unprocessable Entity; RFC 9110 (2022) adopted it into core HTTP as Unprocessable Content. Clients should rely on the number, not the reason phrase.