HTTP 4xx client error status codes
The 4xx class means the server believes the client got something wrong: the syntax, the credentials, the permissions, the target, or the rate. Returning the most precise 4xx code — and a clear, machine-readable error body — turns a frustrating failure into something a developer can fix in seconds. The difference between 400 and 422, or 401 and 403, is not pedantry; clients branch on these codes. Search the reference above by number, name, or symptom to find the right one.
The codes you choose between most often
| Code | Name | Key point |
|---|---|---|
| 400 | Bad Request | Malformed syntax — the request cannot be parsed |
| 401 | Unauthorized | Authentication missing or failed; must send WWW-Authenticate |
| 403 | Forbidden | Identity known, but access denied; re-auth won’t help |
| 404 | Not Found | No resource at this URL |
| 405 | Method Not Allowed | Must send Allow header listing valid methods |
| 409 | Conflict | State conflict — duplicate, version mismatch, etc. |
| 410 | Gone | Permanently removed; tells crawlers to stop indexing |
| 422 | Unprocessable Content | Valid syntax, but business/validation rules failed |
| 429 | Too Many Requests | Rate limited; should send Retry-After |
How it works
When the server detects a client-side problem, it returns a 4xx code and should not retry the request unchanged (the exceptions are 408 Request Timeout and 429 Too Many Requests, which invite a retry). Several codes require specific headers to be valid: 401 needs WWW-Authenticate, 405 Method Not Allowed needs Allow, and 429 should carry Retry-After. A good REST API pairs the status code with a structured body — commonly an RFC 9457 Problem Details document with type, title, status, and detail fields — so clients can display a helpful message and developers can debug without guessing.
Common decision points
400 vs 422
Use 400 Bad Request when the request body cannot be parsed at all — for example, malformed JSON where the parser throws before reaching your validation logic. Use 422 Unprocessable Content when the syntax is valid but the data fails your rules: a missing required field, a string in a field that expects a number, or a date range where the end is before the start.
In practice, many APIs use 400 for both. The distinction matters most when clients branch on status codes to decide how to present errors; using 422 for validation errors makes that branching more reliable.
401 vs 403
401means “prove who you are.” SendWWW-Authenticatein the response so the client knows how to authenticate. The user could gain access by logging in or providing a valid token.403means “I know who you are and the answer is no.” Re-authenticating will not help. Common causes: insufficient role or permission, accessing another tenant’s resource, or trying to delete a locked record.
A deliberate exception: some APIs return 404 when a resource exists but the requester lacks access — this avoids revealing that the resource exists at all, which is an information-hiding choice rather than an error about the URL.
429 rate limiting
A 429 Too Many Requests response should include a Retry-After header (in seconds, or as an HTTP date) and optionally X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers so clients can self-regulate. Well-behaved API clients read Retry-After and back off rather than retrying immediately.
Tips
- Distinguish authentication from authorization:
401(who are you?) versus403(you may not). Mixing them confuses clients and security audits. - Use
422for validation failures and return a field-level error list so forms can highlight exactly what to fix. - On
429, always setRetry-After; well-behaved clients use it to back off instead of hammering your service. - Prefer
410 Goneover404for resources you have intentionally and permanently retired — it is clearer and more cache-friendly for crawlers.