All posts

HTTP Status Codes You Should Actually Know

7 min read

Most developers know 200, 404, and 500. The real debugging starts with the other codes that nobody memorizes.

Most developers know 200, 404, and 500 by heart. The APIs you work with return 201, 204, 301, 304, 401, 403, 422, and 429. If you don't understand what those mean, you're debugging blind.

Your frontend gets a 422. The response is JSON. The request body looks fine. The error message just says "validation failed." Now you're guessing whether the problem is the format, the content, or something the backend decided to reject without telling you.

Here are the HTTP status codes you'll actually encounter day to day — not the full spec, just the ones that show up in real API work:

Code What it means When you'll see it
201 Created POST succeeded, resource created
204 No Content DELETE succeeded, empty body
301 Moved Permanently Resource moved, cached by browser
304 Not Modified Use cached copy
401 Unauthorized Not logged in
403 Forbidden Logged in but no permission
422 Unprocessable Valid JSON, invalid data
429 Too Many Requests Rate limited
502 Bad Gateway Upstream server broken
503 Service Unavailable Temporarily down

The rest of this article covers which ones break your error handling and how to tell them apart.

The Two Codes That Break Error Handlers

A 201 Created means the request succeeded and a resource was created. But plenty of frontend code only checks for 200 and treats everything else as failure. A 201 gets logged as an error and the response body never gets processed.

204 No Content is worse. It means success with no body. It's the standard response for DELETE operations. If your fetch wrapper expects JSON, it will crash trying to parse an empty response. The fix is checking the status code instead of assuming 200.

A 304 Not Modified has the same problem. It returns an empty body because the resource hasn't changed. HTTP caching depends on this. If you're not handling 304, you're downloading the same data on every request. Some backends include cached data in 304 responses anyway, which breaks clients that expect empty bodies. I've seen both patterns cause the same bug from opposite directions.

The Redirect Nobody Codes Correctly

301 vs 302. Both redirect to another URL. The difference is cache behavior.

A 301 Moved Permanently gets cached aggressively by browsers and API clients. Use it for a temporary maintenance redirect and the client will never request the original URL again — even after maintenance ends. A 302 Found means the redirect is temporary. The client should keep using the original URL for future requests.

Some frameworks default to 302 for everything. Others default to 301. If your API client starts skipping endpoints after a deployment, check whether the server returned a 301 somewhere it shouldn't have.

401 vs 403: The Two That Always Get Confused

401 means you're not authenticated. 403 means you're authenticated but not authorized.

A 401 means check your credentials or redirect to login. A 403 means your credentials are valid but the server won't process the request with your current permissions. Retrying the same request won't fix a 403. It might fix a 401 if the client automatically refreshes the token.

There's a browser behavior difference that matters for API design. A 401 triggers a browser login dialog if the browser receives it directly. A 403 doesn't. If you're building an API consumed by browsers, use 401 for expired tokens and 403 for missing roles. Otherwise users get confusing browser dialogs asking them to log in when the real problem is insufficient permissions.

Rate Limiting and Server Errors

429 Too Many Requests includes a Retry-After header telling you when to retry. Ignoring it and retrying aggressively can get you blocked entirely.

500 Internal Server Error is a catch-all that tells you almost nothing. The server knows what broke but chose not to tell you. Check the logs.

$ curl -I https://api.example.com/users
HTTP/2 500

That response tells you nothing useful. A 500 without a body or correlation ID means you're digging through logs.

502 Bad Gateway and 504 Gateway Timeout mean the problem is between servers — proxy, load balancer, CDN origin. Not your application code. 503 Service Unavailable means the server is temporarily overloaded or down for maintenance. Unlike 500, retrying 503 with exponential backoff is the right strategy.

A common pattern in distributed systems: a single upstream service slows down, causing your server to return 504s. The load balancer marks your server unhealthy and returns 502s or 503s. The HTTP status code you see (502) hides the real problem. You need to trace the full request path.

Codes That Look Alike But Aren't

400 Bad Request means the request is malformed. The JSON doesn't parse. The URL is invalid. 422 Unprocessable Entity means the request body is valid JSON but semantically wrong — an email field that doesn't contain an email address. 400 is about parsing. 422 is about validation. The distinction saves time when debugging because it tells you where to look first.

Some APIs never return 422. They return 400 for everything. Others return 422 for every validation error including malformed JSON. The code tells you what the API designer decided, not what the problem actually is.

410 Gone means the resource intentionally removed and won't return. A 404 means the server doesn't know about that URL — it might never have existed. Search engines treat 410 and 404 differently. A 410 tells Google to remove the URL from its index faster. If you're cleaning up deprecated API endpoints, returning 410 instead of 404 helps consumers understand the difference between "this never existed" and "this was removed."

How to Debug a Code You Don't Recognize

  1. Check the range: 2xx (success), 3xx (redirect), 4xx (client error), 5xx (server error). That alone narrows the search.
  2. Read the response body. Many APIs include an error object with a message field.
  3. Check the headers. Retry-After (429), Location (301, 302), WWW-Authenticate (401).
  4. Look for a correlation ID header. It's priceless for finding the request in server logs.
  5. Compare with a known-good request in Postman or curl. The difference is usually a missing header or wrong content type.

These are the HTTP status codes that actually show up in API work. The full reference on this site lists every standard code with example responses. When you get one you've never seen, that's where I'd start.

For the full spec, the Mozilla HTTP Status Code documentation is the best free resource available.