HTTP Status Codes: What 200, 404 and 500 Mean
- HTTP
- status codes
- access logs
- error rate
- error budget
- SLA
- APIs
- integer division
HTTP Status Codes - What 200, 404 and 500 Mean 🚦
9:31 AM, Monday. The trading desk says the market-data API "feels flaky". The head of the desk does not want a feeling, they want a number: how many requests are failing right now, and is it our code or their service? The answer is already on disk. Web servers such as nginx and Apache keep an access log, one line per request, and every line carries a three-digit verdict.
What it is: an HTTP status code is the three-digit number (100 to 599) a server sends back with every response to say how the request went. RFC 9110, the standard that defines what HTTP messages mean, groups the codes into five classes by their first digit.
🧠 The mental model: a postcode
A status code works like a postcode. The first digit is the region; the last two digits pick the exact street. A sorting office that has never seen a particular street still knows which region to send the letter to. RFC 9110 writes that rule into the standard: a client must understand the class of any status code from its first digit, and treat a code it does not recognise as the x00 code of that class. An unfamiliar 599 is handled like a plain 500.
The five classes (RFC 9110)
| Class | What RFC 9110 says it means | Codes you will meet in logs | Whose move? |
|---|---|---|---|
| 1xx Informational | an interim response; the final one is still coming | 101 Switching Protocols (a connection upgrading to a WebSocket price stream) | nobody's yet, it is a progress update |
| 2xx Successful | the request was received, understood and accepted | 200 OK, 201 Created, 204 No Content | done |
| 3xx Redirection | the client must take a further step to complete it | 301 Moved Permanently, 302 Found, 304 Not Modified | the client follows the link or uses its cache |
| 4xx Client error | the request is malformed or cannot be fulfilled | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests | the caller fixes the request |
| 5xx Server error | the server failed on a request that looked valid | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout | the service owner |
The codes people mix up
- 401 vs 403. 401 means "I do not know who you are": the credentials are missing or invalid, so send a valid API key. 403 means "I understood you, and the answer is no": if you sent credentials, they are valid but not enough for this resource, so the fix is a permission, not the same key sent again.
- 502 vs 504. Both come from a gateway or proxy standing in front of the real application. 502: the application behind it sent back an invalid answer (nginx also answers 502 when the application is down and refuses the connection). 504: it sent back no answer in time.
- 304 Not Modified sits in the 3xx class but sends you nowhere: it tells your client that its cached copy is still current, so nothing needs downloading again.
- 429 Too Many Requests (defined in RFC 6585, not RFC 9110) is what a market-data API sends when you poll it too often: slow down. It is a 4xx because the fix is on your side.
The whole classification is one line of Python
The first digit of a three-digit number is what is left after integer division by 100: the // operator divides and throws the remainder away.
404 // 100 -> 4 client error
404 % 100 -> 4 (the remainder: the street, not the region)
Careful with that second line: for 404 the remainder happens to be 4 as well, which is exactly how a wrong formula sneaks through a test on one example. Try both on 503 in your head before you trust either.
From codes to one number: the server error rate
The desk's question has a one-line answer:
server error rate = number of 5xx responses / total requests
Only 5xx counts. A 404 for a ticker that does not exist is the service working correctly: it answered a bad question honestly. Counting it would page the API team (alert whoever is on call) for the caller's mistake.
This ratio is a service level indicator (SLI). The team sets an internal target on it, a service level objective (SLO), usually stricter than the SLA (service level agreement) promised to customers. The failure an SLO still allows is the error budget: an SLO of 99% of requests without a 5xx leaves an error budget of 1%. The budget is counted over a period, often 30 days; the simplest alert, the one your script runs, fires when the error rate in a recent window is above it. A rate of 5% would be burning the budget five times faster than the SLO allows.
🔧 See it for real
# print only the status code of one request
curl -s -o /dev/null -w "%{http_code}\n" https://example.com
# count every status code in an nginx access log (field 9 in the default format)
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c
Your Task
Below is a slice of the market-data API's access log: time, method, path and status code on every line. Classify each status code by its first digit, count the five classes and compute the server error rate, then compare it with the team's 1% error budget. Predict first: scan the last column. How many codes start with a 5, and is the rate over budget? (Once it passes, print the path of every 5xx line: which service should get the page?)
Related terms in the glossary