{{< partial "learn_x_header" >}} **Quick Start:** Learn five mental models that cover every HTTP response, then read live codes with `curl`. Total time: 20 minutes. ## What You'll Learn * What an HTTP status code is, and what problem it solves. * Five mental models that make any code readable, not just the ones you've memorized. * The mnemonic for all five classes, and four more models for the hard cases. * The handful of codes you'll meet 95% of the time. * When the code lies to you (200 with an error inside). * How to read status codes yourself with `curl`. * Where to go to learn the long tail. ## The Basics Every HTTP response carries a three-digit status code: the server's verdict on your request, delivered before any body content. The first digit classifies responses into five categories; knowing those five is enough to read any code you encounter. The registry has over 60 codes, but you can ignore most of them. The five mental models below cover the first digit, the common failure cases, and the specific codes you'll see repeatedly. ### Primary Use Cases * Debugging a failing API call by reading the response, not guessing. * Writing a server that returns honest, correct codes to its clients. * Reading logs and monitoring dashboards where codes are the signal. ### Less Suitable Use Cases * Status codes describe *what* happened, not *why*. For the why, read the response body and headers. * They are not a security boundary. A 403 tells an attacker the resource exists; sometimes 404 is the safer answer. ## Mental Models for HTTP Status Codes A mnemonic helps you memorize the five classes. A mental model helps you *reason* about a code you haven't seen before. These five models work together: the first gets you to the right category, the next three handle the most common confusions, and the last one keeps you honest when a 2xx shows up. ### Mental Model 1: The Five-Class Mnemonic The first digit groups every response into five buckets. 1. **1xx Hold on**: the server got your request and is still working. 2. **2xx Here you go**: success, here's what you asked for. 3. **3xx Go away**: what you want lives somewhere else; go look there. 4. **4xx You messed up**: the request was wrong; fix it and retry. 5. **5xx I messed up**: the request was fine, the server broke. The first digit alone narrows 60-plus codes to one of five categories. Know these five phrases, and you can orient any response before looking up a specific code. ```mermaid graph TB R[Three-digit status code] --> A[1xx Hold on] R --> B[2xx Here you go] R --> C[3xx Go away] R --> D[4xx You messed up] R --> E[5xx I messed up] ``` ### Mental Model 2: The Fault Line When something goes wrong, the first question is: whose bug is it? The 4xx/5xx split answers that in one digit. **4xx** means the request was wrong. The caller sent something the server couldn't use: a missing header, malformed JSON, a nonexistent resource, or a request without credentials. The server did its job by refusing. **5xx** means the server broke. The request was fine, but the server-side failed: an unhandled exception, a crashed database, or an overloaded process. This is the server's problem, not the caller's. That single distinction settles most "whose bug is it?" arguments before they start. One caveat: 4xx is the server's *opinion* that you messed up. The server can be wrong. ```mermaid graph TB E[Something went wrong] --> F{First digit?} F -->|4xx| G[Client sent a bad request] F -->|5xx| H[Server broke] G --> I[Fix the request] H --> J[Wait, retry, or file a bug] ``` ### Mental Model 3: The Identity vs Permission Distinction 401 and 403 both deny access. They signal completely different problems, and mixing them up wastes debugging time. **401 Unauthorized** is an identity question. The server doesn't know who you are. You haven't authenticated, or your session token has expired. The right move: log in or refresh credentials. **403 Forbidden** is a permission question. The server knows exactly who you are and still refuses. Your credentials are valid, but your account lacks the right roles or scopes. The right move: check permissions, not your login. Think of 401 as the server asking "Who are you?" and 403 as the server saying "I know who you are, and no." ```mermaid graph TB A[Access denied] --> B{Which code?} B -->|401 Unauthorized| C[Server does not know who you are] B -->|403 Forbidden| D[Server knows you and denies access] C --> E[Fix: authenticate or refresh token] D --> F[Fix: check roles and scopes] ``` ### Mental Model 4: The Redirect Chain 3xx codes are forwarding addresses. The resource you requested has moved, and the server is pointing you to its current location. **301 Moved Permanently** means you need to update your stored URL. The resource has a permanent new address. Clients, search engines, and caches should all update. **302 Found** (temporary) means keep your original address. The resource is elsewhere for now but may return. Don't update your stored URL yet. **304 Not Modified** is different from both. It isn't a redirect at all: the cached version is up to date, and there's nothing new to download. This saves bandwidth on every repeated request. Browsers follow 3xx redirects automatically. Scripts and CLI tools usually need an explicit flag. In `curl`, that's `-L`. ```mermaid graph TB T[3xx response] --> A{Which code?} A -->|301| B[Permanent: update stored URL] A -->|302| C[Temporary: keep original URL] A -->|304| D[Cache valid: skip the download] ``` ### Mental Model 5: The Two-Layer Trust The HTTP status code is the server's public verdict. The response body is the full story. Either can mislead you. The classic failure: an API returns **200 OK** with an error buried in the JSON body. ```json { "status": 200, "body": { "error": "internal server error" } } ``` GraphQL uses this by design, returning 200 for every request and placing real errors in an `errors` array. Some REST APIs do it by accident when an unhandled exception gets wrapped in a 200 response. The HTTP layer says success while the application layer disagrees. The rule: check the status code first, then read the body before you assume anything worked. The code is the door; the body is the room. ## The Codes You Actually Meet Out of 60-plus codes, these carry almost all daily traffic. Learn these and look up the rest. * **200 OK**: the standard success. The request worked, and the body has your data. * **201 Created**: success, and a new resource now exists (a POST that saved something). * **204 No Content**: success, but there's nothing to return (a DELETE that worked). * **301 / 302 Moved**: redirect. 301 is permanent; 302 is temporary. Your browser follows these automatically. * **304 Not Modified**: your cached copy is still good; save the bandwidth. * **400 Bad Request**: the server couldn't parse what you sent. Malformed JSON, missing fields. * **401 Unauthorized**: "Who are you?" You aren't authenticated. Log in. * **403 Forbidden**: "Who do you think you are?!" You're authenticated, but you can't have this. * **404 Not Found**: no resource at that URL. Could be your typo, could be a bad link the server published. * **429 Too Many Requests**: slow down, you're rate-limited. Back off and retry later. * **500 Internal Server Error**: the server threw an unhandled exception. Not your fault. * **503 Service Unavailable**: the server is up but overloaded or down for maintenance. ## The Famous Joke Code: 418 If you ever see **418 I'm a teapot**, it's real, sort of. It comes from [RFC 2324][rfc2324], the Hyper Text Coffee Pot Control Protocol, an April Fools' joke from 1998. A teapot asked to brew coffee returns 418. Nobody expected it to matter. Then smart kitchen devices arrived; a networked teapot can technically return it and remain compliant. Most frameworks still ship it. It's one of the developer community's favorite inside jokes. ## Build Something: Read Status Codes With curl You don't need a teapot to see status codes. `curl` shows you the real thing in seconds. ### Prerequisites **Required:** * `curl` (preinstalled on macOS and most Linux; available on Windows). * A terminal. * About 5 minutes. **Not required:** * Any account or API key. These hit public test endpoints. ### Step 1: See the status line Use `-I` to fetch just the response headers, including the status line. ```bash curl -I https://httpbin.org/status/200 ``` **Expected output:** ```text HTTP/2 200 date: ... content-type: text/html; charset=utf-8 ``` The `200` on the first line is the verdict. That's the whole game. ### Step 2: Trigger each class on demand `httpbin.org/status/` returns whatever code you ask for. Try one from each class: ```bash curl -o /dev/null -s -w "%{http_code}\n" https://httpbin.org/status/301 curl -o /dev/null -s -w "%{http_code}\n" https://httpbin.org/status/404 curl -o /dev/null -s -w "%{http_code}\n" https://httpbin.org/status/503 ``` **Expected output:** ```text 301 404 503 ``` Here, `-w "%{http_code}\n"` prints only the status code, and `-o /dev/null -s` discards the body and progress meter. This one-liner works for scripting health checks. ### Step 3: Watch a redirect resolve By default, `curl` ignores redirects. Add `-L` to follow the 3xx chain to its destination. ```bash curl -I -L "https://httpbin.org/redirect-to?url=https://example.com" ``` **Expected output:** ```text HTTP/2 302 location: https://example.com HTTP/2 200 content-type: text/html; charset=utf-8 ``` The first response is the 302 redirect, the second is the 200 from the destination. `curl` walked the chain for you. **What you learned:** You can now read any response's verdict, force any code for testing, and trace a redirect. Those three moves cover most real HTTP debugging. ## Troubleshooting **"I get a 200, but the app still shows an error."** The server returned success at the HTTP layer but failed at the application layer. Read the response body. This happens with GraphQL and with APIs that wrap exceptions in 200 responses. **"I'm authenticated but still getting 403."** 403 is about permission, not identity. Your credentials are valid, but your account lacks access to that specific resource. Check roles and scopes, not your login. **"My script's curl returns nothing for a 500."** A 5xx often comes with an empty or HTML body. Print the status code directly with `-w "%{http_code}\n"` rather than relying on body content. ## Learn HTTP Status Codes - Beyond the Basics You've covered the essentials. Here's a curated track to go deeper. Start with the official spec for authority, then keep a visual cheat sheet handy for the codes you forget. 📹 **Video** * [HTTP Status Codes Explained][video-hussein] - Hussein Nasser, YouTube. * [HTTP Crash Course & Exploration][video-traversy] - Traversy Media, YouTube. 🔊 **Audio** * [HTTP 203][audio-http203] - Jake Archibald and Surma's web platform podcast, named after a status code and full of HTTP deep dives. 📚 **Books** * [HTTP: The Definitive Guide][book-http] by David Gourley and Brian Totty - the deep reference for how HTTP really works. * [Web Scalability for Startup Engineers][book-scalability] by Artur Ejsmont - status codes in the context of real web architecture. 🌐 **Online** * [MDN HTTP response status codes][mdn] - the practical, example-rich reference. Bookmark this one. * [RFC 9110: HTTP Semantics][rfc9110] - the authoritative spec for what every code means. * [http.cat][httpcat] - every status code as a cat meme. Genuinely useful for making them stick. * [httpstatuses.com][httpstatuses] - a clean, searchable list with one-line meanings. ## Related Content * [MDN: 100 Continue and the 1xx class][mdn-1xx], for the codes you rarely see but should recognize. * [RFC 2324: Hyper Text Coffee Pot Control Protocol][rfc2324], the home of 418. * [http.dog][httpdog], the same cheat-sheet idea with dogs, if cats aren't your thing. {{< partial "category_footer" >}} [rfc2324]: https://www.rfc-editor.org/rfc/rfc2324 [rfc9110]: https://www.rfc-editor.org/rfc/rfc9110 [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status [mdn-1xx]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/100 [httpstatuses]: https://httpstatuses.com/ [httpcat]: https://http.cat/ [httpdog]: https://http.dog/ [video-hussein]: https://www.youtube.com/watch?v=8XLAj_e7uM4 [video-traversy]: https://www.youtube.com/watch?v=iYM2zFP3Zn0 [audio-http203]: https://http203.libsyn.com/ [book-http]: https://www.oreilly.com/library/view/http-the-definitive/1565925092/ [book-scalability]: https://www.amazon.com/Scalability-Startup-Engineers-Artur-Ejsmont/dp/0071843655