A 422 Unprocessable Entity means the server understood your request, the syntax is valid, but the content does not make sense. The request is well-formed HTTP with valid JSON or form data – nothing is malformed. But the values inside the request violate a rule: a required field is missing, a value is out of range, a relationship is invalid, or a business rule is not satisfied.
This is different from a 400 Bad Request, which means the request itself is broken – malformed JSON, missing headers, or encoding errors. A 400 says “I cannot parse what you sent.” A 422 says “I parsed it fine, but what you are asking for does not make sense.”
Quick reference#
| Symptom | Likely cause | Fix |
|---|---|---|
| 422 on form submission with validation messages | Required fields missing or invalid values | Check the response body for field-level errors and fix the input |
| 422 on API call with valid-looking data | Business rule violation (duplicate email, expired token, invalid state transition) | Read the error response – it tells you which rule failed |
| 422 with “CSRF token mismatch” | Session expired or token not included | Refresh the page to get a new token, or include the token in API requests |
| 422 on WooCommerce checkout | Cart validation failure (out of stock, coupon expired, address invalid) | Check the response body for the specific validation error |
| 422 from a cache service (“cache service responded with 422”) | The cache proxy forwarded a 422 from the origin | Debug the origin server, not the cache layer |
| 422 on file upload | File type not allowed, file too large for application limits, or metadata invalid | Check application-level file validation rules |
422 vs 400 - when to use which#
The distinction between 422 and 400 matters because it tells you where the problem is.
400 Bad Request means the HTTP request is malformed at the protocol level:
- Invalid JSON syntax (missing quotes, trailing comma)
- Wrong Content-Type header for the body format
- Request body too large for the server to accept
- Missing required HTTP headers
- Encoding errors in the URL or body
422 Unprocessable Entity means the HTTP request is perfect, but the application rejects the content:
- An email field contains a string that is not a valid email address
- A date range where the end date is before the start date
- A username that already exists
- A payment amount that is negative
- A state transition that is not allowed (publishing a draft that has no title)
In short: 400 is a transport-level problem. 422 is an application-level problem. If you fix a 400 by changing how you format the request, you fix a 422 by changing what you put in the request.
Some APIs use 400 for everything and never return 422. Others follow the distinction strictly. The HTTP specification does not mandate which one to use for validation errors – both are acceptable. But if an API returns 422, it is telling you the syntax was fine and you should look at the values.
What the HTTP specification says#
HTTP 422 was originally defined in RFC 4918 (WebDAV) and later incorporated into the main HTTP specification in RFC 9110, Section 15.5.21. The current specification calls it “422 Unprocessable Content” (changed from “Unprocessable Entity” in the WebDAV RFC), though most implementations still use the original “Entity” wording.
The specification says: the server understands the content type of the request, the syntax of the request is correct, but it was unable to process the contained instructions.
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"errors": {
"email": ["has already been taken"],
"password": ["must be at least 8 characters"]
}
}
The response body should explain what went wrong. Unlike a 500 Internal Server Error where the server crashed unexpectedly, a 422 is an intentional, expected response. The server is working correctly – it is telling you what to fix.
Common causes#
Validation failures in REST APIs
The most common source of 422 errors. An API endpoint validates the request body and rejects it because one or more fields are invalid:
POST /api/users
Content-Type: application/json
{
"email": "not-an-email",
"password": "short",
"age": -5
}
Response:
HTTP/1.1 422 Unprocessable Entity
{
"message": "Validation failed",
"errors": {
"email": ["must be a valid email address"],
"password": ["must be at least 8 characters"],
"age": ["must be a positive number"]
}
}
The fix is always in the response body. Read the error messages, fix the input, and retry.
CSRF token mismatch
Web frameworks like Laravel, Rails, and Django include a CSRF (Cross-Site Request Forgery) token in forms. If the token is missing, expired, or does not match the session, the framework returns 422:
HTTP/1.1 422 Unprocessable Entity
{
"message": "CSRF token mismatch"
}
This happens when:
- The user’s session expired while the form was open (they walked away and came back)
- The CSRF token was not included in an AJAX request
- A browser extension or proxy stripped the token
- The user has multiple tabs open and one tab’s form submission invalidated the other tab’s token
The fix for end users: refresh the page and resubmit the form. The fix for developers: ensure AJAX requests include the CSRF token in the header or body. In Laravel, for example:
// Include in AJAX headers
axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').content;
WooCommerce checkout validation
WooCommerce returns 422 (or sometimes 200 with error data) when checkout validation fails:
- A required billing or shipping field is empty
- The selected shipping method is no longer available
- A coupon code has expired or does not apply to the cart contents
- An item in the cart is out of stock or the requested quantity exceeds available stock
- The payment gateway rejected the request before processing (invalid card format, missing fields)
WooCommerce’s REST API (
/wp-json/wc/v3/
) returns structured error responses:
{
"code": "woocommerce_rest_invalid_billing_email",
"message": "Invalid billing email address.",
"data": { "status": 422 }
}
If you are building a headless WooCommerce frontend, handle these errors by parsing the response body and displaying the validation message to the user. If you are a store visitor hitting 422 on checkout, try refreshing the page, clearing your cart and re-adding items, or using a different browser. For WooCommerce performance issues that might contribute to stale cart data, check that object caching and page caching are not serving stale checkout pages.
Business rule violations
Some 422 errors are not about invalid data format but about business logic:
- Trying to delete an account that has active subscriptions
- Transferring money from an account with insufficient funds
- Publishing a post that has no title or content
- Assigning a task to a user who does not have the required role
- Creating a duplicate resource that must be unique
These are harder to debug because the request looks valid. The response body is the only clue. A well-designed API explains which business rule was violated:
{
"error": "unprocessable_entity",
"message": "Cannot delete account with active subscriptions",
"details": {
"active_subscriptions": 3,
"action_required": "Cancel all subscriptions before deleting the account"
}
}
Cache service responding with 422
The search term “cache service responded with 422” appears frequently. This means a caching layer (Varnish, Cloudflare, Fastly, or a CDN) forwarded a 422 from the origin server. The cache is not generating the 422 – it is passing it through.
Debug the origin server, not the cache. Bypass the cache and hit the origin directly to confirm:
curl -v https://origin-server.com/api/endpoint \
-H "Host: example.com" \
-H "Content-Type: application/json" \
-d '{"your": "data"}'
If the origin returns 422, the problem is in the application. The cache is just relaying the response.
How to diagnose a 422#
Step 1 – Read the response body
This is the most important step and the one most people skip. A 422 response almost always includes details about what went wrong. Check:
- Browser DevTools: Network tab, click the request, look at the Response tab
- API client (Postman, Insomnia): the response body panel
- curl: add
-vto see the full response
curl -v -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"email": "test", "name": ""}'
Step 2 – Check the request you sent
Compare your request against the API documentation:
- Are all required fields present?
- Are the field types correct (string vs number vs boolean)?
- Are enum values spelled correctly?
- Is the Content-Type header correct?
- Are nested objects structured correctly?
Step 3 – Check for stale state
If the same request worked before and now returns 422:
- A unique constraint was violated (the email was registered between your first and second attempt)
- A resource changed state (an item went out of stock)
- A token expired (CSRF, invitation link, password reset)
- Rate limits changed the server’s behavior (some APIs return 422 instead of 429 for repeated identical requests)
Step 4 – Check server-side logs
If you control the server, check the application logs. Frameworks log validation failures with details that may not be included in the API response:
# Laravel
tail -50 storage/logs/laravel.log
# Rails
tail -50 log/production.log
# Node.js/Express
# Check wherever your application logger writes
Fixing a 422#
As a client (consuming an API)
- Read the error response body – it tells you exactly what to fix
- Fix the invalid fields and retry
- If the error is a CSRF mismatch, refresh your token and retry
- If the error is a business rule violation, address the prerequisite (cancel subscriptions, verify email, etc.)
As a developer (returning 422 from your API)
Return useful error responses. A bare
422 Unprocessable Entity
with no body forces developers to guess. Include field-level validation errors:
// Good - tells the client exactly what to fix
{
"message": "Validation failed",
"errors": {
"email": ["must be a valid email address"],
"password": ["must be at least 8 characters", "must contain at least one number"],
"start_date": ["must be in the future"]
}
}
// Bad - tells the client nothing
{
"error": "Unprocessable Entity"
}
Validate early and return all errors at once. Do not return the first error, make the client fix it, then return the second error. Collect all validation failures and return them in a single response.
Use 422 for semantic errors, 400 for syntax errors. If the JSON is malformed, return 400. If the JSON is valid but the email field contains “asdf”, return 422. This distinction helps API consumers debug faster.
422 vs other 4xx errors#
| Status code | What happened |
|---|---|
| 400 Bad Request | The request is malformed – bad syntax, wrong encoding, missing headers |
| 401 Unauthorized | Authentication required or credentials invalid |
| 403 Forbidden | Authenticated but not authorized for this action |
| 406 Not Acceptable | The server cannot produce a response matching the client’s Accept headers |
| 409 Conflict | The request conflicts with the current state of the resource |
| 422 Unprocessable Entity | The request is well-formed but the content is semantically invalid |
| 429 Too Many Requests | Rate limit exceeded – slow down and retry later |
The closest relative to 422 is 409 Conflict. Both indicate the request is syntactically valid but cannot be processed. The difference: 409 means the request conflicts with the current state of the resource (editing a resource that was modified by someone else, creating a duplicate). 422 means the request itself is invalid regardless of state (a negative age is always wrong, not just wrong right now).
Summary#
A 422 Unprocessable Entity means your request was syntactically valid but the server rejected the content. The fix is almost always in the response body – read the validation errors, fix the input, and retry. For CSRF mismatches, refresh the page. For business rule violations, address the prerequisite condition. If you are building an API, return detailed field-level errors so your consumers can fix problems without guessing.