All posts
5 min read

HTTP Status Codes Explained: 200, 301, 404, 500 and the Rest

Every response from a server starts with a three-digit number that says how it went. What the 2xx, 3xx, 4xx, and 5xx families mean, the dozen codes you'll actually meet, what each one tells you about where a bug lives, and which ones your own API should return.

getting starteddebuggingno-codebeginner

When your browser asks a server for something, the server's reply starts with a three-digit status code. Most of the time you never see it. When something breaks, it's often the single most useful clue you have — because the first digit tells you whose fault it is.

The five families

First digit Meaning In plain English
1xx Informational "Hang on…" (rare; you can ignore these)
2xx Success "Here you go."
3xx Redirection "It's over there."
4xx Client error "You asked for something wrong."
5xx Server error "I broke trying to answer."

That 4xx/5xx split is the big one. A 4xx means the request was the problem: wrong address, not logged in, bad data. A 5xx means the server's code or infrastructure failed. When debugging, it tells you whether to look at what was sent or at what happened on the server.

The codes you'll actually meet

Success

  • 200 OK — worked, here's the result.
  • 201 Created — worked, and a new thing was created (a new user, a new order).
  • 204 No Content — worked, nothing to send back (common after a delete).

Redirects

  • 301 Moved Permanently — this address has moved for good; update your bookmarks. Search engines transfer ranking to the new address.
  • 302 Found / 307 Temporary Redirect — go there for now. Used after logging in, for example.
  • 304 Not Modified — "you already have the latest version cached." A good thing; it saves bandwidth. (What Is Caching?.)

Use 301 when you permanently change a URL (like moving www.yourapp.com to yourapp.com). Use 302/307 for temporary hops.

Client errors (look at the request)

  • 400 Bad Request — the request was malformed or the data was invalid. Missing a required field, badly formatted JSON.
  • 401 Unauthorized — you're not logged in (or your login token expired). Despite the name, it means "not authenticated."
  • 403 Forbidden — you're logged in, but not allowed to do this. (Authentication vs Authorization.)
  • 404 Not Found — nothing at that address. A typo, a deleted item, or a route that doesn't exist.
  • 405 Method Not Allowed — the address exists, but not for that kind of request (a POST to something that only accepts GET).
  • 409 Conflict — clashes with the current state, like signing up with an email that's already taken.
  • 422 Unprocessable Content — the data was well-formed but failed validation. Some APIs use this instead of 400.
  • 429 Too Many Requests — you've hit a rate limit. Slow down. (What Is Rate Limiting?.)

Server errors (look at the server)

  • 500 Internal Server Error — the server's code crashed. The real error is in the server logs, not the browser.
  • 502 Bad Gateway — a server in front of your app (a proxy or load balancer) couldn't get a sensible answer from your app. Often: your app crashed, didn't start, or is listening on the wrong port.
  • 503 Service Unavailable — overloaded or down for maintenance.
  • 504 Gateway Timeout — the server in front waited too long for your app. Something is slow: a heavy database query, a call to an outside API that hangs.

How to see the status code

Open your browser's developer tools, go to the Network tab, and reload. Each request shows its status. Red ones are 4xx and 5xx. Click one to see the full request and response. (Browser Developer Tools for Beginners.)

From the terminal:

curl -I https://yourapp.com/some-page
# HTTP/2 404

What to do with each

You see Look at
400 / 422 The data you're sending. Compare it to what the API expects.
401 Are you logged in? Is the token or cookie being sent? Expired?
403 Does this user have permission? Is a security rule blocking it?
404 The URL: typos, missing IDs, a route that was never deployed.
429 How often you're calling. Add waiting and retries.
500 Server logs. The browser won't tell you more.
502 / 504 Is the app running at all? Did it crash on startup? Is something slow?

A tip for AI-assisted debugging: when you paste an error into Claude Code or another tool, include the status code and the server log line, not just "it doesn't work." "The form returns a 500 and the log says column "email" does not exist" gets fixed in one step. (How to Read an Error Message.)

Returning the right codes from your own API

If you're building an API, return honest codes:

  • Don't return 200 with an error message inside. Clients, monitoring, and retries all rely on the status code.
  • Use 404 for things that don't exist or that the user may not see — returning 403 can confirm to an attacker that the thing exists.
  • Use 401 vs 403 correctly: not logged in versus not allowed.
  • Reserve 5xx for genuine server failures, and make sure each one is logged.

Designing a REST API That Won't Embarrass You Later goes further.


EasySpawn gives Claude Code access to your running app and its server logs in the same workspace, so a 500 in the browser can be traced to the actual error line instead of guessed at. See how it works or join the waitlist.

Related: Anatomy of a URL · What Is an API? · Debugging for Beginners

Keep reading