HTTP 422 Unprocessable Content

HTTP 422 Unprocessable Content is the validation error code. The server successfully parsed the request body — the JSON is syntactically valid, the Content-Type is correct — but the values fail semantic validation. A missing required field, a price below zero, a start date after the end date, an email address that fails format validation: these all produce 422. The response body must include field-level error details or the client cannot know what to fix.

HTTP 422 quick reference →

Quick reference

Code422
NameUnprocessable Content
Category4xx Client Error
SpecificationRFC 9110 §15.5.21
IANA statusAssigned
Cacheable?No
Retryable?Yes — after fixing the payload

The validation error response body

A 422 without field-level details is nearly useless. The client knows the request failed but cannot determine what to fix. A well-structured 422 body follows a consistent schema that clients can parse programmatically:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/json

{
  "error": "validation_failed",
  "message": "The request contains invalid data.",
  "errors": [
    {
      "field": "email",
      "code": "invalid_format",
      "message": "Must be a valid email address."
    },
    {
      "field": "price",
      "code": "out_of_range",
      "message": "Price must be greater than 0.",
      "received": -5
    },
    {
      "field": "end_date",
      "code": "invalid_date_range",
      "message": "End date must be after start date.",
      "received": "2025-01-01",
      "constraint": "start_date is 2025-06-01"
    }
  ]
}

The field uses dot notation for nested fields (address.postal_code) and bracket notation for arrays (items[0].quantity). The code is a machine-readable string the client can switch on. The message is human-readable for display or logging.

Common validation scenarios

Required field missing or empty:

{"name": "", "email": null}
// 422: name cannot be blank, email is required

Format validation: Email addresses, phone numbers, URLs, postal codes, credit card numbers, UUID strings. The value is present but does not match the required format.

Range validation: Numeric values below minimum or above maximum. Strings shorter than minimum length or longer than maximum. Dates outside the allowed window.

Business rule validation: Start date must be before end date. Quantity must be a whole number. Discount percentage cannot exceed 100. Password must contain at least one uppercase letter and one number.

Relationship validation: A referenced entity ID does not exist (e.g., category_id: 999 where category 999 does not exist). This is distinct from a 404 — the request itself is the issue, not the target URL.

Server-side implementation

Express.js with express-validator:

const { body, validationResult } = require('express-validator');

const validateProduct = [
  body('name').notEmpty().withMessage('Name is required'),
  body('price').isFloat({min: 0.01}).withMessage('Price must be positive'),
  body('email').isEmail().withMessage('Must be a valid email'),
];

app.post('/api/products', validateProduct, (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    return res.status(422).json({
      error: 'validation_failed',
      errors: errors.array().map(e => ({
        field: e.path,
        message: e.msg
      }))
    });
  }
  // create product...
});

Django REST Framework: DRF serializers return 422 (via 400 in older DRF, configurable) automatically with field-level errors when validation fails:

class ProductSerializer(serializers.ModelSerializer):
    def validate_price(self, value):
        if value <= 0:
            raise serializers.ValidationError("Price must be positive.")
        return value

    def validate(self, data):
        if data["end_date"] <= data["start_date"]:
            raise serializers.ValidationError(
                {"end_date": "End date must be after start date."}
            )
        return data

FastAPI: FastAPI uses Pydantic models for automatic validation and returns structured 422 errors by default:

from pydantic import BaseModel, validator, EmailStr

class ProductCreate(BaseModel):
    name: str
    price: float
    email: EmailStr

    @validator('price')
    def price_positive(cls, v):
        if v <= 0:
            raise ValueError('Price must be positive')
        return v

# FastAPI automatically returns 422 with Pydantic validation errors

422 vs 400 vs 409

CodeMeaningExample
422Validation failedValid JSON, but email format is wrong
400Parse or syntax errorMalformed JSON (missing closing brace), wrong Content-Type
409Conflict with existing stateEmail is valid format but already registered in the system

Frequently asked questions

What is the difference between 400 and 422?

400 is for request parsing failures: malformed JSON, wrong Content-Type, unparseable syntax. 422 is for semantic validation failures: the request was parsed successfully but the values are invalid according to the server’s rules. A simple heuristic: if the JSON parser threw an exception, it is 400. If the validator threw an exception after successful parsing, it is 422.

Should my API use 400 or 422 for validation errors?

Either is used in practice. The argument for 422: it is semantically precise (parsing succeeded, validation failed). The argument for 400: it is universally understood and older APIs do not distinguish the two. If you choose 400 for validation errors, include the same structured error body as 422 so clients know what to fix.

How should a client handle 422?

Do not auto-retry. Parse the error response body, map the field errors to the corresponding form fields or request parameters, and surface the error messages to the user or operator. Fix the payload based on the error details and resubmit.

Is 422 retryable?

Yes, after fixing the payload. Unlike 500 (server error) or 503 (temporarily unavailable), the issue is with the client’s data, not the server’s state. Correct the failing fields and retry with the corrected data.

Related guides

HTTP 400 Bad Request · HTTP 409 Conflict · HTTP 415 Unsupported Media Type

Comparisons

HTTP 422 vs 409 · HTTP 422 vs 415

Standards reference

Definitions from the IANA HTTP Status Code Registry and RFC 9110 §15.5.21. Human-readable guidance by ErrorLookup. · HTTP 422 quick reference →