Engineering
HTTP Status Codes: A Developer's Cheat Sheet (With Fixes for the Common Errors)
A practical HTTP status code cheat sheet: what every code class means, the ~25 codes you'll actually hit, and how to fix the common 4xx and 5xx errors — with curl examples and a quick client-vs-server guide.
NI
Nikolas Dimitroulakis
Last updated on July 01, 2026
HTTP Status Codes: A Developer's Cheat Sheet (With Fixes for the Common Errors)
Introduction
An HTTP status code is a three-digit number a server returns with every response to tell the client what happened to the request — whether it succeeded, was redirected, failed because of something the client did, or failed on the server. The first digit sets the class:
1xx informational, 2xx success, 3xx redirection, 4xx client error, 5xx server error.That first digit is the fastest triage tool you have. A
4xx means fix your request; a 5xx means the problem is on the server side. You can read any response's status directly:The status line (
HTTP/1.1 200 OK) is the code and its reason phrase. Everything below is about knowing what each one means and, for the ones that break things, what to do about it.The five classes at a glance
| Class | Range | Meaning | Whose move is it? |
|---|---|---|---|
| 1xx | 100–103 | Informational — request received, still processing. | Neither; interim. |
| 2xx | 200–206 | Success — the request worked. | Done. |
| 3xx | 300–308 | Redirection — more steps needed to complete. | Usually the client (follow the redirect). |
| 4xx | 400–429 | Client error — the request was wrong. | You. Fix the request. |
| 5xx | 500–504 | Server error — the server failed to fulfill a valid request. | The server. Retry may help for some. |
The cheat sheet: the codes you'll actually meet
These are the ~25 codes that come up in day-to-day API and web work. The rarer ones exist, but if you know these you can read almost any response.
| Code | Name | What it means | Typical cause / fix |
|---|---|---|---|
| 200 | OK | Standard success, response has a body. | Nothing to do. |
| 201 | Created | A resource was created. | Read the Location header for the new resource URL. |
| 202 | Accepted | Request accepted, processing async. | Poll a status endpoint or wait for a webhook. |
| 204 | No Content | Success, no body returned. | Common for DELETE/PUT. Don't parse a body. |
| 206 | Partial Content | A range of the resource was returned. | Response to a Range request (resumable downloads). |
| 301 | Moved Permanently | Resource has a new permanent URL. | Update your stored URL to the Location value. |
| 302 | Found | Temporary redirect. | Follow Location; don't cache the redirect. |
| 304 | Not Modified | Cached copy is still valid. | Response to a conditional request (ETag/If-None-Match); serve from cache. |
| 307 | Temporary Redirect | Temporary, method preserved. | Re-send the same method to Location. |
| 308 | Permanent Redirect | Permanent, method preserved. | Update the URL; keep the original method. |
| 400 | Bad Request | Request is malformed. | Fix syntax, JSON, or missing required fields. |
| 401 | Unauthorized | Not authenticated. | Send valid credentials; check the WWW-Authenticate header. |
| 403 | Forbidden | Authenticated but not permitted. | Check roles/permissions on the resource. |
| 404 | Not Found | Resource or route doesn't exist. | Verify the path and the resource ID. |
| 405 | Method Not Allowed | Wrong HTTP method for the resource. | Switch to a method in the Allow header. |
| 406 | Not Acceptable | Server can't match your Accept header. | Relax or correct the requested content type. |
| 408 | Request Timeout | Client took too long to send the request. | Retry; check network and payload size. |
| 409 | Conflict | Request conflicts with current state. | Re-fetch, resolve the conflict, retry (e.g. version mismatch). |
| 410 | Gone | Resource permanently removed. | Stop calling it; there's no new location. |
| 415 | Unsupported Media Type | Server rejects the payload's format. | Set the correct Content-Type (e.g. application/json). |
| 422 | Unprocessable Content | Syntax is fine but validation failed. | Fix the field values, not the request format. |
| 429 | Too Many Requests | You've hit a rate limit. | Back off; honor the Retry-After header. |
| 500 | Internal Server Error | Generic server-side failure. | Server-side bug; retry, then report if it persists. |
| 501 | Not Implemented | Server doesn't support the method at all. | Different from 405 — the server never handles this method. |
| 502 | Bad Gateway | An upstream server returned an invalid response. | Usually transient; retry with backoff. |
| 503 | Service Unavailable | Server overloaded or down for maintenance. | Honor Retry-After; retry with backoff. |
| 504 | Gateway Timeout | An upstream server didn't respond in time. | Retry; check upstream health and timeouts. |
2xx: success isn't just 200
Most developers reach for
200 for everything, but the distinctions carry information. 201 Created tells a client a new resource exists and where to find it (in the Location header). 202 Accepted signals asynchronous work — the request was taken but isn't finished, so the client should poll or wait for a callback rather than treat the response as final. 204 No Content is a success with deliberately no body, standard for a DELETE or an update that returns nothing — parsing it as JSON will throw.3xx: redirects and the method trap
Redirects look simple until a
POST turns into a GET. Historically, clients following a 301 or 302 often switched the method to GET, which silently breaks a form submission or an API write. If you need the method preserved across a redirect, the correct codes are 307 (temporary) and 308 (permanent), which mandate keeping the original method. 304 Not Modified is a different animal — it's the payoff of conditional requests: send an If-None-Match with a stored ETag, and a 304 means your cache is still good and no body is sent.4xx: the client errors you'll debug most
This is where most day-to-day debugging lives. The trap is that several of these codes look interchangeable and aren't:
- 400 vs 422 —
400 Bad Requestmeans the request is malformed (broken JSON, wrong syntax).422 Unprocessable Contentmeans the request parsed fine but failed validation (an email field with no@, a negative quantity). If you're getting a 422, stop checking your syntax and start checking your values. - 401 vs 403 —
401 Unauthorizedis about authentication: you're not logged in, or your token is missing or expired.403 Forbiddenis about authorization: you're authenticated, but you're not allowed to do this. A 401 says who are you; a 403 says you can't. - 404 vs 405 —
404 Not Foundmeans the route doesn't exist.405 Method Not Allowedmeans the route exists but rejects your verb. These get confused constantly, and the fix is entirely different — see the dedicated guide on 405 Method Not Allowed for how to read theAllowheader and resolve it. - 409 Conflict — the request clashes with the resource's current state, most often a version mismatch on a concurrent update. Re-fetch the latest state, reapply your change, and retry.
- 429 Too Many Requests — you've exceeded a rate limit. The response frequently includes a
Retry-Afterheader telling you how long to wait:
Honoring
Retry-After (here, 30 seconds) with exponential backoff is the correct handling — hammering a 429 just extends the block.5xx: when it's the server, not you
A
5xx means the server received a valid request and failed to handle it. The practical difference between them tells you whether retrying is worth it:- 500 Internal Server Error — a generic, unhandled server-side failure. There's nothing to fix in your request; retry once, and if it persists it's a bug to report.
- 502 Bad Gateway — a gateway or proxy got an invalid response from an upstream server. Usually transient — retry with backoff.
- 503 Service Unavailable — the server is overloaded or in maintenance. Like a 429, it may include a
Retry-Afterheader; honor it. - 504 Gateway Timeout — a gateway didn't get a response from an upstream server in time. Retry, and if you control the upstream, check its health and timeout settings.
The rule of thumb:
500 and 501 are rarely worth an immediate retry; 502, 503, and 504 are transient often enough that a retry with backoff is the right default.How to inspect a status code
You don't need to guess. Fire the request and read the status line and headers directly.
With curl, the
-i flag includes the response headers so you see the status and the diagnostic headers (Allow, Retry-After, Location, WWW-Authenticate) that tell you what to do next:For interactive work, an API client makes this repeatable. Voiden is an offline-first, Git-native client that stores each request as a Markdown-based
.void file committed alongside your code — so the exact call that produced a 409 or a 422 is versioned and reproducible by anyone on the team, not stuck in one person's local tool. It's open source (Apache 2.0) and you can download it here.Where ApyHub Fits
Reading status codes is one problem; getting consistent, well-documented ones across every API you call is another. When you're wiring up ten different services, each with its own conventions for what a
422 body looks like or whether it returns 200 or 201 on create, the inconsistency is its own source of bugs.ApyHub is a certified API marketplace — a catalog of 200+ APIs and 1,000+ endpoints for common utility work (file conversion, validation, PDF processing, data enrichment, and more). Every endpoint in the catalog ships with a documented, machine-readable specification, including its methods and response shapes, so status-code behavior is predictable before you write the integration — and readable by AI agents consuming the catalog over MCP, not just by humans. It won't stop upstream services from returning a
503, but it removes the guesswork about what a given endpoint returns and when.Conclusion
HTTP status codes are a diagnostic language, not noise. The class digit tells you whose problem it is, the specific code tells you what went wrong, and the response headers —
Allow, Retry-After, Location, WWW-Authenticate — usually tell you how to fix it. Bookmark the table above, learn the pairs that get confused (401/403, 404/405, 400/422, 502/503/504), and most "mystery" errors stop being mysteries.FAQ
What are the five classes of HTTP status codes?
1xx is informational, 2xx is success, 3xx is redirection, 4xx is a client error (the request was wrong), and 5xx is a server error (the server failed on a valid request). The first digit tells you which class a code belongs to.How do I know if an error is my fault or the server's?
Read the first digit. A
4xx code means the problem is in your request — wrong URL, method, credentials, or data — so fixing the request resolves it. A 5xx means the server failed, and the fix is server-side, though retrying with backoff helps for 502, 503, and 504.What's the difference between 401 and 403?
401 Unauthorized means you're not authenticated — your credentials are missing, invalid, or expired. 403 Forbidden means you're authenticated but not permitted to perform the action. In short: 401 is about identity, 403 is about permission.What's the difference between 400 and 422?
400 Bad Request means the request is malformed — broken JSON or invalid syntax the server can't parse. 422 Unprocessable Content means the request was parsed successfully but failed validation, such as a field with an invalid value. A 422 points you at your data, not your formatting.What's the difference between 404 and 405?
404 Not Found means the route or resource doesn't exist. 405 Method Not Allowed means the route exists but doesn't accept the HTTP method you used, and the response includes an Allow header listing the methods it does accept. See the 405 Method Not Allowed guide for the full fix.How should I handle a 429 Too Many Requests error?
Stop sending requests and wait. If the response includes a
Retry-After header, wait that many seconds before retrying; otherwise use exponential backoff. Repeatedly retrying immediately typically extends the rate-limit block rather than resolving it.Which HTTP errors are safe to retry?
Transient server errors —
502 Bad Gateway, 503 Service Unavailable, and 504 Gateway Timeout — are worth retrying with backoff, and 429 after honoring any Retry-After. A 500 is worth one retry at most, and 4xx errors like 400, 401, and 404 won't fix themselves on retry — you have to change the request.What does a 304 Not Modified mean?
It's the successful result of a conditional request: you sent a stored validator (an
ETag via If-None-Match, or a date via If-Modified-Since), and the server confirmed your cached copy is still current, so it returned no body. Serve the resource from your cache rather than re-downloading it.