DEVESSENTIALS

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 @.

4xx · Client errorRFC 9110 §15.5.21

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 detail array gives the location (body, query, path) and field of each error.
  • Rails scaffolded controllers return 422 (:unprocessable_entity, called :unprocessable_content since Rack 3.1) when save fails validation. Rails also responds 422 to a failed CSRF authenticity token check by default.
  • Laravel returns 422 with an errors object 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 of 2, 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 errors array 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-Type at all, e.g. XML sent to a JSON-only API.

Related status codes

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

Browse all developer guides →

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.