Learning & reference
HTTP status codes, with the bit that actually matters
Every code, what it really means, and the QA note that goes with it — plus the four confusions (401/403, 302/307, 502/504, and 200-with-an-error-body) that cause the most bugs.
The five classes
The first digit is the whole story: 1xx still going, 2xx it worked, 3xx look elsewhere, 4xx you made a mistake, 5xx the server made a mistake.
1xx Informational
An interim response. The real one is still coming.
2xx Success
The request was received, understood and accepted.
3xx Redirection
Further action is needed, usually at a different URL.
4xx Client error
The request is wrong. Repeating it unchanged will not help.
5xx Server error
The request was fine; the server failed. Often worth a retry.
1xx Informational
| Code | Name | What it means | QA note |
|---|---|---|---|
| 100 | Continue | Headers received; send the body. | Emitted when a client sends Expect: 100-continue before a large upload. |
| 101 | Switching Protocols | Upgrading, usually to WebSocket. | The handshake response for Upgrade: websocket. |
| 103 | Early Hints | Preload hints before the real response. | Some clients and proxies mishandle it - worth testing. |
2xx Success
| Code | Name | What it means | QA note |
|---|---|---|---|
| 200 | OK | Success, with a body. | Watch for APIs returning 200 with an error object inside - clients then never see a failure. |
| 201 | Created | A new resource exists. | Must include a Location header pointing at it. |
| 202 | Accepted | Queued, not finished. | Asynchronous work. The client needs somewhere to poll. |
| 204 | No Content | Success, no body at all. | A body here is a protocol violation; some clients hang waiting for one. |
| 206 | Partial Content | A byte range, not the whole file. | Powers resumable downloads and video seeking. Test with Range:. |
3xx Redirection
| Code | Name | What it means | QA note |
|---|---|---|---|
| 301 | Moved Permanently | Permanent new URL. | Aggressively cached by browsers - a wrong 301 is very hard to undo. |
| 302 | Found | Temporary redirect. | Historically rewrites POST to GET, which is why 307 exists. |
| 303 | See Other | Fetch the result with GET. | The correct POST-redirect-GET response. |
| 304 | Not Modified | Your cached copy is current. | Sent when If-None-Match / If-Modified-Since match. Has no body. |
| 307 | Temporary Redirect | Temporary, method preserved. | A POST stays a POST - unlike 302. |
| 308 | Permanent Redirect | Permanent, method preserved. | The modern 301 for non-GET requests. |
4xx Client error
| Code | Name | What it means | QA note |
|---|---|---|---|
| 400 | Bad Request | Malformed - the server cannot parse it. | Should not be a catch-all for validation errors; prefer 422. |
| 401 | Unauthorized | You are not authenticated. | Misnamed. Must include WWW-Authenticate. Log in and retry. |
| 403 | Forbidden | Authenticated, but not allowed. | Retrying with the same credentials will never work. The 401/403 mix-up is the classic auth bug. |
| 404 | Not Found | No such resource. | Also used to hide existence from users who lack permission. |
| 405 | Method Not Allowed | Wrong verb for this URL. | Must list the valid verbs in an Allow header. |
| 406 | Not Acceptable | Cannot satisfy Accept. | Rare in practice; most servers just return their default type. |
| 408 | Request Timeout | The client was too slow sending. | Test by opening a connection and stalling mid-body. |
| 409 | Conflict | Clashes with current state. | Duplicate keys, edit conflicts, optimistic-locking failures. |
| 410 | Gone | Deleted on purpose, permanently. | Stronger than 404 - tells crawlers to drop the URL. |
| 411 | Length Required | No Content-Length. | |
| 412 | Precondition Failed | An If-* header did not hold. | The other half of optimistic concurrency with ETags. |
| 413 | Content Too Large | Body exceeds the limit. | The one to test with big uploads - many servers drop the connection instead. |
| 414 | URI Too Long | The URL exceeds the limit. | Usually ~8 KB. Hit it by putting a huge payload in the query string. |
| 415 | Unsupported Media Type | Wrong Content-Type. | Common when a client forgets application/json. |
| 416 | Range Not Satisfiable | The byte range is out of bounds. | Test by requesting a range past end-of-file. |
| 418 | I'm a teapot | An April Fools joke from 1998. | Kept alive by popular demand. Handy as a unique sentinel in tests. |
| 422 | Unprocessable Content | Understood, but semantically invalid. | The right code for validation failures on a well-formed body. |
| 425 | Too Early | Replay risk on a 0-RTT request. | TLS 1.3 early data. |
| 428 | Precondition Required | Send an If-Match. | Forces clients into safe concurrent updates. |
| 429 | Too Many Requests | Rate limited. | Should include Retry-After. Verify your client honours it instead of hammering. |
| 431 | Header Fields Too Large | Headers exceed the limit. | Usually an oversized cookie. |
| 451 | Unavailable For Legal Reasons | Blocked by law. | The number references Fahrenheit 451. |
5xx Server error
| Code | Name | What it means | QA note |
|---|---|---|---|
| 500 | Internal Server Error | Unhandled failure. | Should never leak a stack trace to the client - check that in every environment. |
| 501 | Not Implemented | The server does not support the method. | |
| 502 | Bad Gateway | An upstream returned garbage. | The proxy reached your app and disliked the answer. |
| 503 | Service Unavailable | Down or overloaded, probably briefly. | Should carry Retry-After. The correct code during deploys and maintenance. |
| 504 | Gateway Timeout | The upstream never answered. | The proxy gave up waiting - distinct from 502. |
| 505 | HTTP Version Not Supported | ||
| 507 | Insufficient Storage | The server is out of space. | |
| 511 | Network Authentication Required | A captive portal is intercepting. | Seen on hotel and airport Wi-Fi. |
The four confusions worth testing
401 vs 403
401 = we do not know who you are, authenticate and try again. 403 = we know exactly who you are and you still may not. Returning 403 to a logged-out user sends them to a dead end instead of the login page.
302 vs 307
A 302 after a POST is historically rewritten to a GET, silently dropping the body. 307 and 308 preserve the method. If a form submission mysteriously loses data on redirect, this is why.
502 vs 504
502 means the upstream answered with something invalid; 504 means it never answered at all. They point at completely different failures.
200 with an error body
The worst anti-pattern: HTTP 200 wrapping
{"error": "..."}. Every retry, alert and monitor treats it as success, so failures are invisible.
Trigger any status on demand
The HEXAQA worker returns whatever code you ask for, so you can prove your client handles it - including retries, redirect chains and timeouts.
Any status
gen.hexaqa.com/status/503
Redirect chain
gen.hexaqa.com/redirect/5
Stall before responding
gen.hexaqa.com/delay?ms=5000