< HTTP/1.1 422 Unprocessable Content422 Unprocessable Entity (Unprocessable Content) Explained
422 Unprocessable Content (formerly Unprocessable Entity): the JSON parsed but failed validation. FastAPI, Laravel and Rails errors, 422 vs 400, RFC 9457.
- Cacheable
- Only with explicit freshness
- Retry?
- No: fix the payload
- Usually sent by
- Origin app
On this page
TL;DR: 422 Unprocessable Content means the server rejected the data in your request, usually because a field failed validation. Read the response body, fix the named field or missing CSRF token, then resend the corrected request.
What you see in your client
The messages and response bodies here are illustrative. Client messages use https://api.example.com/resource; reason phrases and URLs can vary.
- Axios:
AxiosError: Request failed with status code 422with the default status handling. Inspecterror.response.datafor the server’s explanation. Axios source. - fetch: the promise resolves with
response.status === 422andresponse.ok === false. Check the status before reading the body; HTTP errors do not entercatchautomatically. MDN fetch. - Python requests:
requests.exceptions.HTTPError: 422 Client Error: Unprocessable Entity for url: https://api.example.com/resourcewhen you callresponse.raise_for_status(). Requests source. - curl -f:
curl: (22) The requested URL returned error: 422. Usecurl -iwithout-fwhile inspecting the error body. curl source. - .NET:
HttpRequestExceptionwith the English messageResponse status code does not indicate success: 422 (Unprocessable Entity).afterEnsureSuccessStatusCode(). Runtime message template. - Spring WebClient:
WebClientResponseException$UnprocessableEntity: 422 Unprocessable Entity from POST https://api.example.com/resourcewithretrieve(). ReadgetResponseBodyAsString(). Spring 6.2 source. - Spring RestTemplate (6.2):
HttpClientErrorException$UnprocessableEntity: 422 Unprocessable Entity on POST request for "https://api.example.com/resource": [no body]with the default error handler and an empty response body. Read the exception body when present. Message builder, exception subclasses.
Spring 7 adds WebClientResponseException$UnprocessableContent: 422 Unprocessable Content from POST https://api.example.com/resource. Both names identify status 422. Spring source.
What it means
RFC 9110 section 15.5.21 defines 422 as: the server understands the content type and the syntax is correct, but it was unable to process the contained instructions. Typical triggers are a missing required field, a wrong data type, an email that fails a format rule, or a business rule such as an end date before the start date. The name was “Unprocessable Entity” in WebDAV (RFC 4918); RFC 9110 renamed it “Unprocessable Content”. Libraries and older docs still use either phrase.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://example.com/problems/validation-error",
"title": "Your request parameters didn't validate.",
"status": 422,
"errors": [
{ "field": "email", "message": "must be a valid email address" },
{ "field": "age", "message": "must be at least 18" }
]
}
What you actually see in each framework
FastAPI (Pydantic v2) answers with a detail array where loc is the path to the bad field:
{
"detail": [
{ "type": "missing", "loc": ["body", "email"], "msg": "Field required", "input": {} }
]
}
Laravel validation produces this JSON shape when the request expects JSON; a traditional form submission redirects back with session errors:
{
"message": "The email field is required.",
"errors": { "email": ["The email field is required."] }
}
Rails maps ActionController::InvalidAuthenticityToken (“Can’t verify CSRF token authenticity”) to 422. For form re-renders with errors, controllers choose the status: Turbo displays failed submissions when the response uses a 4xx status such as 422. The GitHub REST API returns 422 with "message": "Validation Failed" and an errors array of resource, field and code. Spring MVC request validation and Django REST framework serializer validation default to 400; inspect their error bodies for the failing fields. Spring mappings, DRF exceptions.
Common causes by stack
- FastAPI / Pydantic: missing fields or invalid path, query and body values produce 422 with a
detailarray;locstarts with the input location. Fix the named input, not just the JSON body. FastAPI validation. - Laravel:
$request->validate(...)throwsValidationExceptionon failure; requests expecting JSON receive 422 withmessageanderrors. SendAccept: application/jsonfor an API workflow and fix the rule named in the error. CSRF token mismatches map to 419. Validation docs, exception handler. - Rails:
ActionController::InvalidAuthenticityTokenmaps to 422; restore the CSRF token and matching session cookie. For model validation, the controller chooses the response status; render the failed form with 422 for Turbo. Rails mappings, Turbo form handling. - Express: the
safeParsehandler below explicitly selects 422 for schema errors; fix the reportedfieldpath. Express’s JSON parser uses 400 for malformed JSON, so keep parser failures separate from this handler. Express parser errors.
FastAPI also returns 422 for malformed JSON: its router wraps JSONDecodeError in RequestValidationError, with type: "json_invalid" and msg: "JSON decode error". That is a framework convention beyond the RFC’s semantic-validation definition. Fix the JSON syntax before looking for a field rule. FastAPI router source.
Fix it as the client
- Read the response body; do not stop at the status line. The field name is in
loc,errorsordetails. - Compare field types to the API schema:
"qty": "2"vs2, dates in ISO 8601 (2027-01-31T10:00:00Z), enums with the exact casing. - Check for required fields you sent as
nullor an empty string. - For Rails CSRF 422s, send the token in
X-CSRF-Tokenand make sure the session cookie is attached (see cookie not sent).
Reproduce with curl so you can see the raw body:
curl -sv -X POST https://api.example.com/users \
-H 'Content-Type: application/json' \
-d '{"email":"not-an-email","age":-5}'
Handling 422 in a workflow
With FastAPI, loc: ["query", "limit"] points to the URL query, while ["body", "items", 0, "quantity"] points to the first item in a JSON array. Laravel uses dotted error keys for nested fields, such as users.0.email. Match these paths to form fields so users can correct the rejected value. Keep the submitted data available while displaying the error; a status-only alert loses the field information the server already supplied. FastAPI errors, Laravel response format.
A workflow retry should use corrected input. For a validation failure, route the error body to the step that collects or transforms the data. For a Rails CSRF failure, refresh the page’s token and session before submitting again. If the response contains json_invalid, validate the serialized bytes instead of changing field values. These are different repairs for the same status number; choose from the response body and the framework that sent it.
Build it as the API author
Return all validation errors at once, in one machine-readable shape. RFC 9457 application/problem+json is the standard container:
// Express with a schema validator such as zod
app.post('/users', (req, res) => {
const result = userSchema.safeParse(req.body)
if (!result.success) {
return res.status(422).type('application/problem+json').json({
type: 'https://example.com/problems/validation-error',
title: "Your request parameters didn't validate.",
status: 422,
errors: result.error.issues.map((i) => ({ field: i.path.join('.'), message: i.message }))
})
}
res.status(201).json(createUser(result.data))
})
Keep secrets out of error output. Use 409 Conflict when valid data conflicts with current server state; reserve 422 for instructions the API rejects as invalid.
422 versus neighbors
- 400 Bad Request: broken syntax, unparseable JSON, or a framework that does not distinguish validation.
- 409 Conflict: the data is valid but clashes with current server state.
- 415 Unsupported Media Type: the body format itself is not accepted.
- 413 Content Too Large (formerly Payload Too Large): the body is over a size limit.
The request builder lets you send an invalid body and inspect the response.
See also the comparison 400 vs 422: which of the two to return for validation errors and what common frameworks default to.
Frequently asked questions
How should a workflow handle a 422 error?
Read and preserve the validation response, map its field paths back to the input step, and resend corrected data. FastAPI uses loc paths and Laravel uses dotted errors keys; for a Rails CSRF failure, restore the token and matching session cookie.
What does 422 Unprocessable Content mean?
The server understood the content type and the body parsed correctly, but the data inside is semantically invalid, for example a missing required field, a malformed email or a negative quantity. It was called "Unprocessable Entity" in WebDAV (RFC 4918) and renamed in RFC 9110; the status number is unchanged.
What is the difference between 422 and 400?
400 means the request could not be parsed or is malformed at the syntax level, such as broken JSON. 422 means the syntax was fine but the values failed validation. Many APIs, including Spring and Django REST framework by default, return 400 for both, so follow whatever your API documents.
Why does FastAPI return 422?
FastAPI validates request data with Pydantic and automatically answers 422 with a detail array that lists each failing field under loc, with a msg and type. Read loc to find the field, for example ["body", "email"], and msg for the reason.
Why do I get 422 Invalid Authenticity Token in Rails?
Rails raises ActionController::InvalidAuthenticityToken, rendered as 422, when a form or fetch request lacks a valid CSRF token. Include the csrf_meta_tags value as an X-CSRF-Token header for AJAX, and confirm the session cookie is being sent.
Should I use 400 or 422 in my own API?
Either is defensible. Use 400 for syntax errors and 422 for validation failures if you want clients to distinguish them, and return the same machine-readable error body for both. Pick one convention and document it.
Sources
Related
400 vs 422: Malformed vs Invalid Requests
400 Bad Request or 422 Unprocessable Content for validation errors? The syntax-vs-semantics rule, what Rails, Laravel, FastAPI and Spring return by default, and raw examples.
400 Bad Request
400 Bad Request means the server could not parse your request. Find which layer sent it, fix bad JSON and oversized cookies or headers, and reproduce with curl.
405 Method Not Allowed
405 Method Not Allowed means the URL exists but not for that method. Read the Allow header, then fix redirects turning POST into GET, static hosting and WAFs.
406 Not Acceptable
The server cannot produce a response matching the client's Accept headers. Learn about content negotiation and how to handle format mismatches.
408 Request Timeout
408 Request Timeout means the server gave up waiting for the client to finish sending. Tune nginx, Apache, Node and ALB timeouts and tell it apart from 504.