HTTP Status Codes Reference — Complete Searchable Guide with Real-World Examples

May 25, 2026 · 14 min read

Every HTTP request your browser, API client, or server makes results in a status code. That three-digit number is the first thing any debugging session starts with, and the last thing many developers actually understand. This reference covers every standard HTTP status code from 1xx informational responses through 5xx server errors, with real-world usage examples, common root causes, debugging tips, and ready-to-use code snippets in JavaScript and Python.

Unlike dry RFC listings, this guide explains when and why each code appears in production systems. A 301 redirect sounds simple until you discover your CDN is caching it permanently and your users cannot reach the new URL. A 503 is straightforward until your load balancer starts returning it during deployments and your monitoring pages you at 3 AM. The details matter, and this reference provides them.

Interactive Status Code Search

Search by code number, name, or keyword. Click any card to expand its full description, real-world example, debugging tips, and code snippets for handling it in JavaScript and Python.

Understanding HTTP Status Code Categories

HTTP status codes are grouped into five classes, each identified by the first digit. Understanding these categories gives you an immediate mental model for diagnosing any response, even codes you have never seen before.

1xx Informational (100-199): These are provisional responses. The server has received the request headers and the client should proceed to send the request body (in the case of 100 Continue) or switch protocols (101 Switching Protocols for WebSocket upgrades). You rarely encounter these in application code because HTTP libraries handle them internally, but they are essential for performance optimization. The Expect: 100-continue header lets clients avoid sending large request bodies when the server would reject them based on headers alone, saving bandwidth on failed uploads.

2xx Success (200-299): The request was received, understood, and accepted. The most common are 200 (OK), 201 (Created for POST requests), and 204 (No Content for successful operations with no response body). A subtle but critical distinction: 200 means the response body contains the requested representation, while 204 means the action succeeded but there is nothing to return. Using 200 with an empty body instead of 204 can confuse client parsers that expect JSON.

3xx Redirection (300-399): Further action is needed to complete the request. The critical distinction here is between 301 (permanent, cacheable indefinitely) and 302/307 (temporary, not cached). Misusing 301 when you mean 302 can cause browsers and CDNs to cache the redirect for months, making it effectively impossible to reverse without cache purges. For APIs, 308 (Permanent Redirect) preserves the HTTP method, which 301 does not guarantee.

4xx Client Error (400-499): The request contains an error on the client side. This is the largest and most nuanced category. The difference between 400 (malformed syntax), 401 (needs authentication), 403 (authenticated but not authorized), and 422 (valid syntax but semantically wrong) determines whether the client should fix its request, re-authenticate, request different permissions, or correct its business logic. Getting these right in your API dramatically reduces support tickets.

5xx Server Error (500-599): The server failed to fulfill a valid request. These always indicate a bug, misconfiguration, or infrastructure failure on the server side. The client did nothing wrong. The most common are 500 (generic server error), 502 (bad gateway, meaning a reverse proxy could not reach the upstream), 503 (service temporarily unavailable, often during deployments or overload), and 504 (gateway timeout, the upstream took too long to respond).

The 10 Most Common Status Codes in Production

Based on analysis of real-world API traffic patterns, these ten codes account for over 95% of all HTTP responses in production systems:

200 OK dominates at roughly 70-85% of all responses in healthy systems. If your 200 rate drops below 90%, investigate immediately. 301 and 302 redirects typically account for 5-10%, mostly from URL normalization (adding trailing slashes, www/non-www canonicalization, HTTP-to-HTTPS upgrades). 304 Not Modified is a cache hit, meaning the client's cached version is still fresh. High 304 rates are excellent; they mean your caching strategy is working.

400 Bad Request usually indicates malformed JSON, missing required fields, or invalid query parameters. 401 and 403 are authentication and authorization failures, respectively. A spike in 401s often means an API key rotation did not propagate to all clients. 404 Not Found is the most visible error to end users and often results from broken links, deleted content, or URL typos. 500 Internal Server Error is the catch-all for unhandled exceptions. 502 and 503 are infrastructure-level errors that typically indicate deployment issues, upstream crashes, or capacity problems.

Debugging Status Codes: A Systematic Approach

When you encounter an unexpected status code, follow this systematic approach rather than guessing:

Step 1: Read the response body. Most well-designed APIs include an error message, error code, and sometimes a documentation link in the response body. Do not just look at the status code in isolation. The body of a 400 response might say {"error": "validation_failed", "field": "email", "message": "Invalid email format"}, which tells you exactly what to fix.

Step 2: Check the response headers. Headers like Retry-After (on 429 and 503), WWW-Authenticate (on 401), Location (on 3xx), and X-Request-Id (for correlating with server logs) provide critical debugging context. The X-RateLimit-Remaining header tells you how close you are to hitting rate limits before you actually get a 429.

Step 3: Reproduce with curl. Strip the request down to its minimal form using curl. This eliminates client library bugs, middleware interference, and cookie/session issues. If curl returns a different status code, the problem is in your HTTP client, not the server.

Step 4: Check server logs. For 5xx errors, the server-side log is the source of truth. Look for the stack trace associated with the request ID. For 4xx errors, check if the server is logging the reason for rejection, which often differs from what the response body says due to security considerations (servers intentionally return vague errors to prevent information leakage).

Status Code Best Practices for API Design

If you are building an API, choosing the right status codes is one of the most impactful decisions you will make for developer experience. Here are battle-tested guidelines:

Be specific, not generic. Returning 400 for every client error forces developers to parse error messages to understand what went wrong. Instead, use 400 for malformed syntax, 401 for missing auth, 403 for insufficient permissions, 404 for non-existent resources, 409 for conflicts (duplicate creation), 422 for valid syntax but invalid semantics, and 429 for rate limiting. Each code triggers different client-side handling logic.

Always include a machine-readable error body. The status code tells you the category of the problem; the body tells you the specifics. Use a consistent error schema across your entire API: {"error": {"code": "RESOURCE_NOT_FOUND", "message": "User with ID 42 not found", "details": []}}. This lets clients build generic error handling that works for every endpoint.

Use 201 with a Location header for resource creation. When a POST creates a resource, return 201 Created with a Location header pointing to the new resource's URL. Return the created resource in the body. This follows REST conventions and lets clients immediately navigate to or cache the new resource without a second request.

Return 204 for successful operations with no body. DELETE, PUT (when the client sent the full representation), and some PATCH operations do not need a response body. Using 204 instead of 200 with an empty object makes the intent explicit and avoids client-side JSON parsing errors on empty responses.

Use 429 with Retry-After for rate limiting. Always include a Retry-After header (in seconds) so clients can implement exponential backoff correctly. Also include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers so well-behaved clients can throttle themselves before hitting the limit.

Handling Status Codes in Code

Every HTTP client library has its own patterns for handling status codes. Here are robust patterns for the two most common languages in API development:

JavaScript (fetch API): The fetch API does not reject on HTTP errors. A 404 or 500 response resolves the promise successfully. You must check response.ok (which is true for 200-299) or response.status explicitly. This is the most common source of bugs in frontend code: developers assume fetch will throw on errors like axios does.

// Robust fetch wrapper with status code handling async function apiRequest(url, options = {}) { const response = await fetch(url, options); if (response.status === 204) return null; // No content if (response.status === 301 || response.status === 308) { return apiRequest(response.headers.get('Location'), options); } if (response.status === 429) { const retryAfter = response.headers.get('Retry-After') || 5; await new Promise(r => setTimeout(r, retryAfter * 1000)); return apiRequest(url, options); // Retry } if (!response.ok) { const error = await response.json().catch(() => ({})); throw new HttpError(response.status, error.message || response.statusText); } return response.json(); }

Python (requests library): The requests library does not raise exceptions on HTTP errors by default either. You must call response.raise_for_status() to convert 4xx/5xx responses into exceptions, or check response.status_code manually. The raise_for_status() approach is cleaner for simple scripts, but manual checking gives you more control for nuanced handling.

import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry # Automatic retry on 429, 502, 503, 504 session = requests.Session() retries = Retry(total=3, backoff_factor=1, status_forcelist=[429, 502, 503, 504], respect_retry_after_header=True) session.mount("https://", HTTPAdapter(max_retries=retries)) response = session.get("https://api.example.com/users/42") if response.status_code == 200: user = response.json() elif response.status_code == 404: print("User not found") elif response.status_code == 401: print("Token expired, re-authenticating...") else: response.raise_for_status() # Raises for any other error

Frequently Asked Questions

What is the difference between 401 Unauthorized and 403 Forbidden?

A 401 means the request lacks valid authentication credentials. The client should re-authenticate by sending a login token, API key, or session cookie. A 403 means the server understood the request and the client is authenticated, but the client does not have permission to access the resource. Re-authenticating will not help because the problem is authorization, not authentication.

When should I return a 404 vs a 410 status code?

Use 404 Not Found when a resource does not exist at the given URL but might exist in the future, or when you do not want to reveal whether it ever existed. Use 410 Gone when the resource previously existed and has been permanently removed. Search engines treat 410 as a stronger de-indexing signal. For APIs, 410 tells clients to stop retrying the endpoint.

What causes a 502 Bad Gateway error and how do I fix it?

A 502 occurs when a reverse proxy (Nginx, Cloudflare, AWS ALB) receives an invalid response from the upstream server. Common causes: the backend application crashed, the proxy_pass URL is misconfigured, the backend ran out of memory, or firewall rules are blocking the connection. Fix it by checking upstream logs, verifying the backend is running, increasing proxy timeout values, and confirming the upstream address and port.

What is the correct status code for rate limiting?

The standard code is 429 Too Many Requests (RFC 6585). Include a Retry-After header with the number of seconds to wait. Good APIs also include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers so clients can track quota usage proactively.

Should I use 200 OK or 204 No Content for a successful DELETE?

Use 204 No Content when the DELETE succeeds and you have no response body to return. Use 200 OK when you include a confirmation message or the deleted resource in the body. Some APIs use 202 Accepted for asynchronous deletion where the resource is queued for removal. The rule: no body means 204, body means 200.

Related Tools