Developer Tools

Reading HTTP Status Codes Like a Backend Engineer: A Local Reference Guide You Can Use Without a Network

15 min read
HTTP status codes reference for backend engineers

Every backend engineer has stared at a cryptic three-digit code in server logs at 2 AM, opened a browser tab, and waded through RFC quotes and Stack Overflow threads just to confirm what 502 actually means. That friction gets worse when the network is flaky, your on-call VPN drops mid-search, or the team runs air-gapped environments where Google is not an option. You need the answer now, not after three redirects through outdated forum posts. By the end of this guide you will have a working mental model for every HTTP status code class, know how to tell the most confusing failure codes apart, and have a local reference tool that removes the search step entirely.

Why a Local HTTP Reference Beats Googling Every Code

The standard workflow goes like this: you see a code in a log line, open a browser, search for it, parse a wall of RFC quotes and conflicting Stack Overflow answers, and finally extract the sentence you needed. That round-trip is slow, network-dependent, and often returns outdated or incomplete explanations. RFC 9110 revised the entire HTTP semantics spec in 2022, yet half the search results still cite RFC 7231 or even RFC 2616, which can steer you toward wrong assumptions about redirect behavior or cache semantics.1

CapyToolkit’s HTTP Status Code Reference runs entirely client-side. Once the page loads, every IANA-registered code across the 1xx through 5xx classes, every unofficial vendor code from Cloudflare and nginx, and every framework-specific pattern for Express, Django, FastAPI, Next.js, Spring Boot, and Python requests works offline with zero network calls. Your data never leaves the browser, which is consistent with how free browser-based tools from CapyToolkit that process everything locally work. Type a number like 429 to find rate-limit codes instantly, search “timeout” to surface 408 and 504, or browse by class pill when you only know the failure tier. You can look up any HTTP status code in your browser without a network connection, copy a Markdown summary for a Jira ticket, and close the tab in under ten seconds.

Use it as a daily companion alongside your terminal and monitoring dashboard. When an alert fires and you need to know whether 502 means “upstream crashed” or “upstream timed out,” the answer is one search away, no Google required.

The Five Classes: A Mental Model for Every Code

HTTP status codes split into five classes by their first digit. That single digit tells you what kind of response you are looking at before you read the specific code, and it immediately narrows your debugging path: if the class is 4xx, fix the client; if the class is 5xx, fix the server. The table below maps each class to its meaning and the action you should take. The MDN HTTP response status codes reference provides a complete catalog of every registered code, but for daily triage you only need the class rules.

ClassMeaningAction
1xxInformationalContinue processing; no user-facing action
2xxSuccessRequest succeeded; proceed normally
3xxRedirectionFollow the redirect or use the cached copy
4xxClient ErrorFix the request before retrying
5xxServer ErrorRetry later; the fault is server-side

1xx Informational

The server received the request and is continuing to process it. 100 Continue lets a client with a large request body start transmitting only after the server signals readiness, which avoids wasting bandwidth on a body the server would reject.2 101 Switching Protocols confirms a protocol upgrade such as a move to WebSockets. 102 Processing signals that the server is working on a long-running WebDAV request, and 103 Early Hints lets a CDN send resource hints before the final response arrives.34 You rarely handle these explicitly in application code because they are implementation details of the HTTP connection itself.

2xx Success

The server received, understood, and accepted the request. 200 OK is the baseline success response for a GET or PUT; 201 Created follows a write that adds a new resource and should include a Location header pointing at it; 204 No Content is the cleanest choice for a successful DELETE that returns no body, since it tells the client the action succeeded without wasting bandwidth on an empty payload. 202 Accepted means the request was received but processing is asynchronous, which is common for long-running tasks. 206 Partial Content supports range requests, letting a client resume a large download without starting over.

3xx Redirection

The client must take an additional action, usually a request to a different URI, to complete the operation. 301 Moved Permanently signals a permanent move that search engines and caches can store indefinitely, while 302 Found marks a temporary detour that keeps the original address authoritative. 304 Not Modified tells the client its cached copy is still valid, letting the browser skip the download and reuse stored headers instead. The critical distinction between the older 301/302 pair and the newer 308/307 pair is method preservation: 308 and 307 require the client to repeat the same HTTP method when following the redirect, while 301 and 302 allow clients to downgrade the request to a GET.3

4xx Client Errors

The request contains bad syntax, missing authorization, or a logical state the server refuses to act on. The fault lies with the client, so retrying the unchanged request produces the same outcome. 400 covers structurally malformed requests that the parser cannot interpret; 401 and 403 both cover access problems but distinguish between an unknown identity and a known-but-unauthorized one; 404 covers resources that cannot be found at the requested address; 429 signals rate limiting. When you need a deeper breakdown of the full client-error range, the guide to HTTP 4xx client error codes covers every code with causes and resolution steps.

5xx Server Errors

The server failed to fulfil a request that the client formed correctly. The fault is server-side, so the client can often retry the same request later and succeed once the underlying problem resolves. 500 Internal Server Error is the generic catch-all for an unexpected condition; 502 and 504 point to upstream dependency problems; 503 signals that the server is deliberately refusing traffic because it is overloaded or in maintenance. The guide to HTTP 5xx server error codes breaks down each code with specific debugging paths.

Reading Real-World Failure Codes

Some codes look similar on the surface but point to completely different root causes. Three pairs cause the most debugging time because engineers reach for the wrong fix first.

502 vs 503 vs 504

When a proxy or load balancer sits between the client and the origin, that intermediary can report three different failure modes. 502 Bad Gateway means your reverse proxy received an invalid response from upstream. The upstream is running but returned garbage, maybe because it crashed mid-response or returned malformed headers. 503 Service Unavailable means the server is overloaded or in maintenance, and a Retry-After header tells you when to try again. 504 Gateway Timeout means the upstream did not respond in time. The upstream is silent, not malformed, which makes 504 different from 502.

The practical shortcut: if you see 502, check whether the upstream process is running and healthy; if you see 503, check server capacity and maintenance windows; if you see 504, check network connectivity and timeout configuration between the proxy and the upstream.

401 vs 403

401 Unauthorized means the request lacks valid credentials. The server does not know who you are, and the response must include a WWW-Authenticate header prompting the client to supply credentials.5 403 Forbidden means your identity is confirmed but you lack permission for this specific resource. Retrying with the same credentials will not help because the identity itself is insufficient for the action.

The debugging path splits here: 401 means “fix authentication,” while 403 means “fix authorization.” If your token is expired, you get 401. If your token is valid but your role lacks the required permission, you get 403.

404 vs 410

Authentication problems tell you who can reach a resource; the next pair tells you whether the resource exists at all. 404 Not Found means the server cannot find a resource at the requested URI, and it may return later. 410 Gone means the resource existed and was deliberately removed; it will not return. A 410 response is cacheable by default, so caches store it and stop forwarding requests to the origin for that URI.6 Google treats 404 and 410 similarly for indexing purposes, but 410 makes the permanent-removal intent explicit in your logs and monitoring alerts.7

HTTP Status Codes in API Design

Choosing the right status code is a contract decision. Your code tells the client what to do next without reading the body, which means the wrong code violates the contract and forces client developers to guess. Use 200 OK for successful reads, 201 Created with a Location header for resource creation, and 204 No Content for successful deletes. Never return 200 OK with an error body; that forces every client to parse the body just to discover the request failed.

For error cases, use 400 Bad Request for malformed syntax, 409 Conflict for duplicate key violations, and 422 Unprocessable Content for well-formed but semantically invalid payloads. The distinction matters because a 422 tells the client “your JSON was valid but the business rule rejected it,” while a 400 says “your JSON was broken and I could not parse it.” Use 429 Too Many Requests with a Retry-After header for rate limiting so the client knows to back off instead of hammering the server.8

Use 500 only when the fault is truly unexpected. For upstream failures, choose 502, 503, or 504 to communicate the specific failure mode; clients and monitoring systems can route each code to a different alert channel or retry strategy. Consistent error response bodies make your API predictable. RFC 9457 Problem Details defines a standard format that includes a machine-readable type URI, a human-readable detail, and an instance URI, giving clients both a programmatic error code and a message they can display or log without custom parsing.9

The HTTP status codes in REST API design guide covers the full selection rules for 2xx, 4xx, and 5xx, while the API error response design guide shows how to structure consistent error bodies with field-level validation errors and correlation IDs.

Here is a decision checklist for the trickiest codes:

  1. Validation failure: return 400 if the request is structurally broken (malformed JSON, missing required field), or 422 if the structure is valid but business rules reject it.
  2. Resource conflict: 409 when the request conflicts with the current state (duplicate email, version mismatch), versus 422 for semantically invalid values (end date before start date).
  3. Rate limiting: return 429. Always include a Retry-After header.
  4. Upstream failure: 502 for invalid upstream responses, 503 for overloaded or in-maintenance servers, 504 for upstream timeouts.

Framework-Specific Patterns

Every framework has its own idiom for returning status codes. The reference tool covers six popular frameworks, and the patterns below are the ones you will reach for most often.

Express.js and Django REST Framework

Express uses a chainable res.status() method:

app.get('/users/:id', (req, res) => {
  const user = findUser(req.params.id);
  if (!user) {
    return res.status(404).json({ error: 'User not found' });
  }
  res.json(user);
});

Django REST Framework uses constants from rest_framework.status:

from rest_framework import status
from rest_framework.response import Response

def retrieve(self, request, pk=None):
    user = find_user(pk)
    if not user:
        return Response(
            {"error": "User not found"},
            status=status.HTTP_404_NOT_FOUND
        )
    return Response(user)

Express lets you chain .status() and .json() in one statement, which is concise but means every error path must explicitly call .status(). DRF requires importing the status constants, which makes the code more verbose but self-documenting; a constant like HTTP_404_NOT_FOUND leaves no ambiguity about what you intended. Both approaches are explicit about the status code, which matters when a teammate reads the endpoint six months later and needs to understand every code path at a glance. The trade-off is between Express’s brevity and DRF’s readability, and teams that mix both stacks often settle on a convention like wrapping Express responses in a helper function that mirrors DRF’s constant pattern. For deeper patterns like error middleware and custom exception handlers, the Express status codes guide and the Django REST Framework status guide cover real-world examples.

FastAPI and Next.js

FastAPI uses exception-based control flow:

from fastapi import HTTPException

@app.get("/users/{user_id}")
def get_user(user_id: int):
    user = find_user(user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

Next.js differs by router. The Pages Router uses res.status(), while the App Router uses NextResponse.json() with a status option:

// App Router (Next.js 15+)
import { NextResponse } from 'next/server';

export async function GET(request, { params }) {
  const { id } = await params;
  const user = findUser(id);
  if (!user) {
    return NextResponse.json(
      { error: 'User not found' },
      { status: 404 }
    );
  }
  return NextResponse.json(user);
}

FastAPI’s HTTPException approach means you raise errors instead of returning them, which keeps the happy path linear and pushes error handling to exception middleware; this pattern works well with dependency injection because your route handlers stay focused on business logic while a global handler formats the error body consistently. Next.js splits its approach between two routers, so check which one your project uses before writing status code logic; the Pages Router follows an Express-like pattern while the App Router uses NextResponse, and mixing them in the same project is a common source of inconsistency. The FastAPI status codes guide and the Next.js API routes status guide detail both patterns with examples. When you consume APIs from the browser, the Fetch API error handling guide explains how to build a wrapper that throws on 4xx and 5xx responses so you never silently swallow a server error.

Spring Boot and Python requests

Spring Boot uses annotations and ResponseEntity:

@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
    User user = userRepository.findById(id)
        .orElseThrow(() -> new ResponseStatusException(
            HttpStatus.NOT_FOUND, "User not found"));
    return ResponseEntity.ok(user);
}

Python requests reads status codes from the client side:

import requests

response = requests.get("https://api.example.com/users/42")
if response.ok:
    print(response.json())
else:
    response.raise_for_status()  # raises HTTPError for 4xx/5xx

Spring Boot’s @ResponseStatus annotation lets you attach a status code to an exception class, and ResponseEntity gives you full control over the response including headers and body. The @ControllerAdvice pattern is the idiomatic way to centralize error handling across all controllers; each exception type maps to a status code and body format in one place, which prevents individual controllers from returning inconsistent codes for the same failure. Python requests provides response.status_code for direct inspection, response.ok for a boolean check that returns true for any status below 400 (including 2xx and 3xx), and response.raise_for_status() to convert any 4xx or 5xx into an exception that halts execution.10 The Spring Boot status codes guide and the Python requests status guide cover each approach in depth.

Quick Reference and Next Steps

Bookmark the HTTP Status Code Reference and use it as your daily companion. Type a code number to find it, search a keyword to discover related codes, or browse by class pill when you only know the failure tier. The tool works offline after the first load, which is useful in air-gapped environments, on flaky networks, or when you are on-call and cannot afford a Google detour.

When you encounter a code in production, follow this sequence: read the class first (1xx through 5xx) to identify the failure tier, read the specific code to narrow the cause, check for Retry-After or Location headers that the standard defines for that code, and match the code to the framework idiom your team uses. This four-step read gives you enough context to decide whether to retry, re-authenticate, follow a redirect, or file a server-side bug without opening another browser tab. The caching and status codes guide explains which codes are cacheable by default under RFC 9110, and the HTTP status codes and SEO impact guide covers how search engine crawlers interpret each code for indexing and crawl budget. For production environments behind Cloudflare, the Cloudflare error codes reference decodes every 520 through 527 variant so you can distinguish an origin timeout from an SSL handshake failure without guessing. If your infrastructure uses nginx, the nginx custom status codes guide explains non-standard codes like 444, 495, and 499 that appear in access logs but nowhere in the RFC series.

Sources
  1. 1.

    RFC Editor Team, “STD 97, RFC 9110 on HTTP Semantics,” lists.w3.org, June 2022. https://lists.w3.org/Archives/Public/ietf-http-wg/2022AprJun/0132.html

  2. 2.

    Mozilla Developer Network, “100 Continue - HTTP,” developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/100

  3. 3.

    “List of HTTP status codes,” Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/List_of_HTTP_status_codes

  4. 4.

    Cloudflare, “Early Hints,” developers.cloudflare.com, accessed June 2026. https://developers.cloudflare.com/cache/advanced-configuration/early-hints/

  5. 5.

    Mozilla Developer Network, “401 Unauthorized - HTTP,” developer.mozilla.org, accessed June 2026. https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/401

  6. 6.

    R. Fielding, M. Nottingham, and J. Reschke, “HTTP Semantics,” RFC 9110, IETF, June 2022. https://datatracker.ietf.org/doc/html/rfc9110

  7. 7.

    Google, “How HTTP Status Codes Affect Google’s Crawlers,” developers.google.com, February 2026. https://developers.google.com/crawling/docs/troubleshooting/http-status-codes

  8. 8.

    M. Nottingham and R. Fielding, “Additional HTTP Status Codes,” RFC 6585, IETF, April 2012. https://datatracker.ietf.org/doc/html/rfc6585

  9. 9.

    M. Nottingham, E. Wilde, and S. Dalal, “Problem Details for HTTP APIs,” RFC 9457, IETF, July 2023. https://www.rfc-editor.org/info/rfc9457/

  10. 10.

    Python Requests developers, “Developer Interface,” docs.python-requests.org, accessed June 2026. https://docs.python-requests.org/en/latest/api/#requests.Response.ok

More in Developer Tools