HTTP Status Codes Every Developer Should Know
A practical reference for HTTP status codes ā the five categories, deep dives on 200, 201, 204, 301, 302, 304, 400, 401, 403, 404, 409, 422, 429, 500, 502, 503, plus guidance on REST API design and debugging in DevTools.
HTTP status codes are the language servers use to tell clients what happened with a request. Every developer encounters them constantly ā in DevTools, in API responses, in error logs, in Slack alerts at 3am. Knowing what each code actually means, when to use which code in your own APIs, and what common ones signal about a bug makes you significantly faster at debugging and building better services.
You can look up any HTTP status code with the BrowseryTools HTTP Status Code Reference ā free, no sign-up, everything runs in your browser.
The Five Categories
Status codes are three-digit numbers. The first digit defines the category:
- 1xx ā Informational: The request was received; processing continues. These are rare in most applications.
- 2xx ā Success: The request was received, understood, and accepted.
- 3xx ā Redirection: Further action is needed to complete the request. The client should follow a redirect.
- 4xx ā Client Error: The request was malformed or unauthorized. The client made a mistake.
- 5xx ā Server Error: The server failed to fulfill a valid request. The server made a mistake.
This first-digit rule is important: if you see a status code you do not recognize (like 429 or 451), you can at least know whether the problem is on the client or server side, and whether the request ultimately succeeded.
2xx: Success Codes
These tell the client the request worked. The specific code communicates how it worked:
- 200 OK ā the universal success. The response body contains the requested data. Used for GET requests and most responses that return content.
- 201 Created ā a new resource was created. Should include a
Locationheader pointing to the new resource's URL. Use this for POST requests that create records, not 200. - 204 No Content ā the request succeeded but there is no body to return. Common for DELETE requests and PATCH/PUT operations where the client does not need updated data back. The response must not include a body.
- 206 Partial Content ā used with range requests (the
Rangeheader). Video players use this to request specific byte ranges of a media file without downloading the whole thing.
# REST API design pattern POST /api/users ā 201 Created (body: new user object, Location: /api/users/123) GET /api/users/123 ā 200 OK (body: user object) PATCH /api/users/123 ā 200 OK (body: updated user) or 204 No Content DELETE /api/users/123 ā 204 No Content
3xx: Redirect Codes
Redirects tell the client to look somewhere else. The Location header contains the new URL. The key distinction is between permanent and temporary redirects, and between redirects that preserve the HTTP method and those that change it.
- 301 Moved Permanently ā the resource has a new permanent URL. Browsers and search engines cache this. The browser will use GET for the redirect regardless of the original method (a historical quirk). Use this when permanently renaming a URL or redirecting HTTP to HTTPS in an older setup.
- 302 Found ā temporary redirect. Like 301, browsers change POST to GET on the redirect (per the spec, though the spec was "wrong" ā see 307). Use 302 only when the redirect is genuinely temporary.
- 304 Not Modified ā the cached version is still fresh; there is no body. The server sends this in response to a conditional GET (with
If-None-MatchorIf-Modified-Since). The browser uses its cached copy. Important for CDN efficiency and reducing bandwidth. - 307 Temporary Redirect ā like 302, but the spec guarantees the original HTTP method is preserved. If a POST results in a 307, the browser will POST to the new URL. Use 307 instead of 302 for non-GET temporary redirects.
- 308 Permanent Redirect ā like 301, but also guarantees method preservation. The modern standard for permanent redirects.
Common Misconception: 301 vs 302 for SEO
Search engines treat 301 as a signal to transfer "link equity" (PageRank) from the old URL to the new one and update their index. A 302 tells the crawler the redirect is temporary, so it keeps indexing the original URL. Using 302 when you mean 301 can suppress the SEO benefit of redirects. Conversely, using 301 when the redirect is temporary causes search engines to cache the redirect, making it harder to undo.
4xx: Client Error Codes
These codes indicate the client sent a bad request. Do not return 5xx for client mistakes ā that misleads monitoring and makes it harder to identify whether a problem is a bug in your server or bad input from a client.
- 400 Bad Request ā the request is malformed. Missing required fields, invalid JSON, wrong data types. The most generic 4xx; use more specific codes when available.
- 401 Unauthorized ā despite the name, this means "not authenticated." The client provided no credentials, or the credentials were invalid. The response should include a
WWW-Authenticateheader indicating how to authenticate. The name is a historical mistake ā "unauthenticated" would be more accurate. - 403 Forbidden ā authenticated but not authorized. The server knows who you are (or it does not matter who you are) and you do not have permission. Unlike 401, re-authenticating will not help. Use 403 when a user tries to access a resource they are not permitted to see.
- 404 Not Found ā the resource does not exist at this URL. Also returned when a server wants to hide the existence of a resource from unauthorized users (returning 403 would confirm the resource exists; returning 404 hides that fact).
- 409 Conflict ā the request conflicts with the current state of the resource. Classic example: trying to create a user with an email that already exists, or trying to update a resource using a stale version (optimistic locking conflict).
- 422 Unprocessable Entity ā the request is syntactically correct (valid JSON, right Content-Type) but semantically invalid (a required field is present but contains an invalid value, business rule violation). Rails popularized using 422 for validation errors. More specific than 400.
- 429 Too Many Requests ā rate limit exceeded. Should include a
Retry-Afterheader telling the client how long to wait. Essential for any public API.
401 vs 403: The Distinction That Matters
This is one of the most commonly confused pairs:
GET /api/admin/users Authorization: (none) ā 401 Unauthorized "You haven't told me who you are. Log in first." GET /api/admin/users Authorization: Bearer <valid-regular-user-token> ā 403 Forbidden "I know who you are. You're not an admin. Access denied."
5xx: Server Error Codes
- 500 Internal Server Error ā a generic catch-all for unexpected server-side failures. An unhandled exception, a null reference, a database query that threw an error. Do not expose stack traces to clients; log them server-side.
- 502 Bad Gateway ā the server acting as a proxy or gateway received an invalid response from an upstream server. Common when your load balancer or reverse proxy cannot reach the application servers behind it ā the app crashed or is not listening on the right port.
- 503 Service Unavailable ā the server is temporarily unable to handle requests. Could be overloaded, in the middle of a deployment, or doing maintenance. Should include a
Retry-Afterheader when the outage duration is known. - 504 Gateway Timeout ā the proxy or gateway did not receive a timely response from the upstream server. The upstream is up and responding, but too slowly. Common symptom of database queries that are taking too long or external API calls that are hanging.
Status Codes in REST API Design
Using the right status codes makes your API self-documenting and easier to integrate against. A few guidelines:
- Never return 200 with an error object in the body. If a request failed, the status code should reflect that. Clients should be able to check the status code alone to know if they need to handle an error.
- Use 201 and a
Locationheader when creating resources via POST. This allows clients to discover the new resource's URL without parsing the body. - Return 422 (not 400) for validation errors, and include a structured error body that identifies which fields failed and why.
- Use 409 for conflicts that require application-level resolution, not just bad input.
- Implement 429 with rate limiting from the start on any public-facing endpoint ā it is much harder to add retroactively.
Debugging Status Codes in DevTools
Open the Network tab in browser DevTools and look for requests in red ā those are 4xx or 5xx responses. Click a request to see the exact status code, the response headers (useful for WWW-Authenticate, Location, Retry-After), and the response body (which often contains an error message from the server). For redirects, check "Preserve log" so the DevTools panel does not clear when the page navigates ā otherwise you miss the redirect chain.
When you encounter an unfamiliar status code, the BrowseryTools HTTP Status Code Reference gives you the official description, the RFC it comes from, and notes on common usage ā without having to leave your browser tab.
Free HTTP Status Code Reference ā All Codes, RFC Sources, Usage Notes
Open HTTP Status Reference āTry the Tools ā 100% Free, No Sign-Up
Everything runs in your browser. No uploads. No accounts. No ads.
Explore All Tools ā