HTTP 4xx Client Error Codes — 400, 401, 403, 404, 409, 422, 429 Explained
HTTP 4xx status codes indicate client errors. Here's when to use 400 Bad Request vs 422 Unprocessable Entity, the difference between 401 and 403, what 409 Conflict means, and...
HTTP 4xx codes tell clients the request failed because of something on their end. Choosing the right 4xx code helps API consumers understand what to fix without guessing.
Use the HTTP Status Codes Reference to quickly look up any status code.
400 Bad Request
The request is syntactically malformed — the server can’t process it:
400 — Use when:
- Request body is invalid JSON
- Required field is missing
- Field type is wrong (string instead of number)
- Content-Type header is missing or wrong
POST /api/users
Content-Type: application/json
{"email": "alice" ← malformed JSON, missing closing brace
HTTP/1.1 400 Bad Request
{"error": {"code": "BAD_REQUEST", "message": "Invalid JSON body"}}
401 Unauthorized
The request requires authentication and none was provided (or the credentials are invalid):
401 — Use when:
- No Authorization header
- Bearer token is expired
- API key is invalid
- Basic auth credentials are wrong
GET /api/profile
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
{"error": {"code": "UNAUTHENTICATED", "message": "Authentication required"}}
The WWW-Authenticate header tells the client what auth scheme to use.
403 Forbidden
The client is authenticated but lacks permission for the resource:
403 — Use when:
- User is logged in but can't access another user's data
- API token has insufficient scope
- IP is blocked
- Resource requires a different role (admin only)
GET /api/users/999/profile ← user 123 trying to access user 999
HTTP/1.1 403 Forbidden
{"error": {"code": "FORBIDDEN", "message": "You can only access your own profile"}}
401 vs 403: 401 = “I don’t know who you are.” 403 = “I know who you are, but you can’t do this.”
404 Not Found
The resource doesn’t exist:
404 — Use when:
- /api/users/999 and user 999 doesn't exist
- Route path doesn't exist in the API
Note: Some APIs return 404 even for “resource exists but you can’t see it” to avoid leaking information. This is intentional and valid — choose based on your security requirements.
405 Method Not Allowed
The HTTP verb isn’t supported for this endpoint:
DELETE /api/articles/123 ← endpoint is read-only
HTTP/1.1 405 Method Not Allowed
Allow: GET, POST
{"error": {"code": "METHOD_NOT_ALLOWED", "message": "DELETE is not allowed on this endpoint"}}
Include the Allow header listing valid methods.
409 Conflict
The request conflicts with the current state of the resource:
409 — Use when:
- Creating a user with an email that already exists
- Trying to check out a branch that's already checked out
- Optimistic concurrency: update fails because resource changed since last read
- Trying to publish something already published
POST /api/users
{"email": "alice@example.com"} ← email already registered
HTTP/1.1 409 Conflict
{"error": {"code": "DUPLICATE_EMAIL", "message": "An account with this email already exists"}}
410 Gone
The resource existed but has been permanently deleted:
410 — Use when:
- User deleted their account and URL should be tombstoned
- An API endpoint has been permanently removed
- A blog post was deleted and should be deindexed by search engines
Unlike 404, which is ambiguous, 410 explicitly signals “this was here, it’s gone, don’t come back.”
422 Unprocessable Entity
The request is well-formed but semantically invalid:
422 — Use when:
- Request body parses fine but field values fail validation
- Email format is invalid
- Date is in the past when a future date is required
- Referenced foreign key doesn't exist
POST /api/users
{"email": "not-an-email", "age": -5}
HTTP/1.1 422 Unprocessable Entity
{
"error": {
"code": "VALIDATION_ERROR",
"details": [
{"field": "email", "message": "Must be a valid email"},
{"field": "age", "message": "Must be a positive number"}
]
}
}
400 vs 422: 400 = can’t parse the request at all. 422 = parsed fine, values are wrong.
429 Too Many Requests
The client has exceeded the rate limit:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1715000000
{"error": {"code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Try again in 60 seconds."}}
Always include Retry-After so clients know when to retry. Use Retry-After: <seconds> or an HTTP-date.
Quick reference
| Code | Name | When to use |
|---|---|---|
| 400 | Bad Request | Malformed syntax, wrong content-type |
| 401 | Unauthorized | Not authenticated |
| 403 | Forbidden | Authenticated but not allowed |
| 404 | Not Found | Resource doesn’t exist |
| 405 | Method Not Allowed | Wrong HTTP verb |
| 409 | Conflict | State conflict (duplicate, optimistic lock) |
| 410 | Gone | Permanently deleted resource |
| 422 | Unprocessable Entity | Validation failure |
| 429 | Too Many Requests | Rate limit exceeded |
Related tools
- HTTP Status Codes Reference — full status code lookup
- REST API Error Handling — error response design
- HTTP Redirect Codes — 3xx redirect guide
Related posts
- When to Use 422 vs 400 (and Other HTTP Status Code Debates) — 400 means the request is malformed. 422 means it's valid but semantically wrong.…
- HTTP 301 vs 302 Redirect — Permanent vs Temporary Redirects Explained — Understand when to use 301 (permanent) vs 302 (temporary) redirects, how they af…
- HTTP 404 Not Found — What It Means and How to Fix It — HTTP 404 means the server understood the request but can't find the resource. It…
- HTTP Redirect Status Codes — 301, 302, 307, 308 Explained — HTTP 3xx redirect codes tell clients to look elsewhere for a resource. Here's wh…
- HTTP Status Codes Reference — Complete Guide to All Response Codes — HTTP status codes tell clients what happened with their request. Here's a comple…
Related tool
Full HTTP status code reference with explanations and when to use each.
Written by Mian Ali Khalid. Part of the Dev Productivity pillar.