Skip to content
KubeAtlas
HTTP API SRE Networking

HTTP Status Codes: The Complete Reference Guide

Onur Ömer Tunç 8 min read

1xx — Informational

CodeNameWhat it means
100ContinueServer received the request headers; client may send the body. Used with Expect: 100-continue for large file uploads.
101Switching ProtocolsProtocol switch approved. Returned during HTTP → WebSocket upgrades (Upgrade: websocket).
102ProcessingWebDAV: server is processing the request, no response yet. Prevents timeouts on long-running operations.
103Early HintsLink headers sent before the final response. Used at CDN and edge to preload critical resources.
SRE note: Seeing 101 in Kubernetes ingress logs for WebSocket connections is normal. For nginx ingress, don't forget nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" and proxy-send-timeout: "3600" — otherwise the ingress will cut the connection.

2xx — Successful

CodeNameWhat it means
200OKStandard success response. Body content varies by method: GET → resource, POST → operation result, PUT → updated resource.
201CreatedResource created. The Location header should contain the URI of the new resource. Used with POST and PUT.
202AcceptedRequest received; processing continues asynchronously. Used for job/queue operations that can't return a result immediately.
203Non-Authoritative InformationResponse was modified by a proxy or cache. Metadata may differ from the origin.
204No ContentSuccess with no body. Standard for DELETE and some PUT operations.
205Reset ContentClient should reset the form or view. Used in browser form resets.
206Partial ContentPartial content returned via Range header. Used for large file downloads, video streaming, and resumable downloads.
207Multi-StatusWebDAV: status for multiple resources returned in the XML body within a single request.
208Already ReportedWebDAV: already reported in a previous response within the same binding.
226IM UsedHTTP delta encoding: the server applied one or more instance manipulations.
SRE note: If you have an API using 202, always define a polling mechanism or webhook callback strategy. "Request accepted" does not mean "completed" — document this distinction for clients and track the 202 → completion time as a separate metric in monitoring.

3xx — Redirection

CodeNameWhat it means
300Multiple ChoicesMultiple options available; client must choose (e.g. different language or format). Rarely used.
301Moved PermanentlyResource permanently moved. Browsers and search engines cache the new URL from the Location header.
302FoundTemporary redirect. After a POST, browsers typically follow with a GET (PRG pattern).
303See OtherAlways redirect with GET after POST/PUT/DELETE. Standard behavior after form submission.
304Not ModifiedCache is valid; no body sent. Response to conditional requests with If-None-Match / If-Modified-Since. Critical for bandwidth savings.
307Temporary RedirectTemporary redirect; method does not change (POST → POST). This is the key difference from 302.
308Permanent RedirectPermanent redirect; method does not change. Preferred over 301 for HTTPS migrations.
SRE note: Use 308 instead of 301 for HTTP → HTTPS migrations. With 301, browsers cache the original method and may convert POST requests to GET. Kubernetes ingress with ssl-redirect: "true" returns 308 — that's the correct behavior. Check redirect chains: curl -L -v https://domain.com 2>&1 | grep -E "< HTTP|Location" — more than two redirect hops is costly for SEO.

4xx — Client Errors

CodeNameWhat it means
400Bad RequestServer could not understand the request. Malformed syntax, invalid parameter, or missing required field.
401UnauthorizedAuthentication required or failed. The WWW-Authenticate header indicates the expected auth scheme.
402Payment RequiredPayment required. Many SaaS APIs use this when a rate limit is exceeded.
403ForbiddenIdentity confirmed but access to this resource is not permitted.
404Not FoundResource not found. Either doesn't exist or intentionally hidden (as a security measure instead of 403).
405Method Not AllowedThis HTTP method is not valid for this endpoint. The Allow header lists permitted methods.
406Not AcceptableServer cannot produce a response in the format specified in the Accept header. Content negotiation failed.
407Proxy Auth RequiredLike 401 but for proxy authentication.
408Request TimeoutClient did not complete the request within the allowed time. Server closed the connection.
409ConflictRequest conflicts with the current state of the resource. Simultaneous updates, duplicate records, or version mismatch.
410GoneResource permanently deleted and will not return. Important for SEO — search engines remove the URL from their index.
411Length RequiredContent-Length header is required but was not sent.
412Precondition FailedIf-Match / If-Unmodified-Since condition failed. Used for optimistic locking.
413Content Too LargeRequest body exceeds the server's accepted limit. File upload size limit exceeded.
414URI Too LongURL is longer than the server can process. Usually caused by excessively long query strings.
415Unsupported Media TypeContent-Type is not supported by the server. Like sending XML to a JSON API.
416Range Not SatisfiableRange header is invalid or exceeds the resource size.
417Expectation FailedThe condition in the Expect header cannot be met by the server.
418I'm a TeapotEaster egg from RFC 2324: a teapot refusing to brew coffee.
421Misdirected RequestRequest directed to a server unable to produce a response. Seen in HTTP/2 multiplexing issues.
422Unprocessable ContentSyntax is valid but semantic errors exist. Standard for form validation errors.
423LockedWebDAV: resource is locked.
424Failed DependencyWebDAV: this request failed because another operation it depended on failed.
425Too EarlyRequest sent with early data (0-RTT) rejected due to replay risk. Related to TLS 1.3.
426Upgrade RequiredClient must upgrade to the specified protocol. The Upgrade header indicates which protocol is required.
428Precondition RequiredConditional request (If-Match) is mandatory — the resource must not be updated blindly.
429Too Many RequestsRate limit exceeded. The Retry-After header indicates when to try again.
431Header Fields Too LargeHeaders are too large. Large cookies or too many custom headers.
451Unavailable For Legal ReasonsContent blocked for legal reasons. Country-based restrictions or court orders.
SRE note: Always set the Retry-After header for 429 and write clients that implement exponential backoff. APIs without rate limiting are exposed to cascade failure under load spikes. Wire up a Prometheus alert on http_requests_total{status="429"} — a sudden spike in 429s means either an attack or a client stuck in a loop.

5xx — Server Errors

CodeNameWhat it means
500Internal Server ErrorGeneral server error. Catch-all: unexpected exception, null pointer, unhandled error.
501Not ImplementedServer does not support this HTTP method. Seen in partial HTTP implementations.
502Bad GatewayProxy/gateway received an invalid response from the upstream server. The most common 5xx — pod not ready or in a crash loop.
503Service UnavailableServer temporarily out of service. Overloaded or in maintenance mode.
504Gateway TimeoutProxy/gateway did not receive a timely response from upstream. Pod is responding but the ingress timeout was exceeded.
505HTTP Version Not SupportedServer does not support the HTTP version used in the request.
506Variant Also NegotiatesContent negotiation led to a circular reference. Misconfiguration.
507Insufficient StorageWebDAV: not enough storage to complete the operation.
508Loop DetectedWebDAV: infinite loop detected.
510Not ExtendedAdditional extension required to fulfill the request.
511Network Auth RequiredAuthentication required to access the network. Seen on captive portals (WiFi login pages).
Debugging 502 and 504 in Kubernetes:

502 Bad Gateway → Pod not ready, in a crash loop, or listening on the wrong port
504 Gateway Timeout → Pod is responding but the ingress timeout was exceeded

502 debug steps:

# Check that pods are Running and Ready
kubectl get pods -n <namespace> -o wide

# Verify endpoints are registered
kubectl get endpoints <service-name> -n <namespace>

# Look at pod logs
kubectl logs -n <namespace> <pod-name> --previous

# Check that the service selector matches the pod labels
kubectl describe service <service-name> -n <namespace>

For 504, increase ingress timeouts:

nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "120"
nginx.ingress.kubernetes.io/proxy-read-timeout: "120"

Monitoring HTTP Status Codes with Prometheus

groups:
  - name: http_errors
    rules:
      - alert: HighErrorRate5xx
        expr: |
          sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
          /
          sum(rate(http_requests_total[5m])) by (service)
          > 0.01
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.service }}: 5xx error rate > 1%"

      - alert: SuddenSpike4xx
        expr: |
          sum(rate(http_requests_total{status=~"4.."}[5m])) by (service)
          > 50
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.service }}: 4xx spike detected"

Which Code for Which Scenario — REST API Quick Reference

ScenarioCorrect Code
Successful GET request200 OK
Resource created via POST201 Created
Successful DELETE, no body204 No Content
Async job queued202 Accepted
Form validation error422 Unprocessable Content
Duplicate record (email already exists)409 Conflict
No token or invalid token401 Unauthorized
Valid token, insufficient permission403 Forbidden
Resource not found404 Not Found
Rate limit exceeded429 Too Many Requests
Unexpected server error500 Internal Server Error
Tags HTTP API SRE Networking