200 OK
Success response defined by RFC 9110 §15.3.1.
Last updated July 27, 2026
Common causes at a glance
- The request succeeded and the server returned a representation
- An API returning application-level errors inside a 200 envelope
- A catch-all route or SPA fallback serving index.html for a URL that does not exist
- A load balancer or error page short-circuiting the origin with a 200 body
Reproduce it
curl -i https://www.example.com/What 200 OK means
The important thing about 200 is how little it promises. It confirms the
server understood the request and produced a representation. What that representation
means depends on the method: for GET it is the target resource, for
POST the result of the action, for HEAD the headers a
GET would have returned with no body.
That gap is where most 200-related bugs live. An API returning
{"error": "not found"} with a 200 is well-formed HTTP and useless to every
cache, retry policy, and dashboard in the path. Status codes are the only part of the
response intermediaries reason about.
What the spec says
RFC 9110 §15.3.1 defines 200 and lists payload
semantics per method. Two consequences are easy to miss. A 200 to GET or
HEAD is heuristically cacheable unless the method definition or explicit
cache directives say otherwise (RFC 9111 §4.2.2), which is why an
accidental 200 on an error page can be served from a CDN for hours. And a 200 to a
request that created something should have been 201 with a
Location header (§10.2.2).
What actually causes it
Nobody debugs a legitimate 200. The interesting failure is a 200 that
should have been something else. Single-page-app hosting is the biggest offender: a
catch-all rewrite serving index.html for every unmatched path turns broken
deep links into 200s, and search engines index thousands of empty pages as a result.
GraphQL is second, since the spec puts errors in the response body, so a resolver blowing
up still returns 200 and alerting sees a healthy error rate. Third are frameworks that
wrap everything in {"success": false}. All three break retries, circuit
breakers, and cache invalidation, because none of those look inside bodies.
How to debug it
When a 200 is suspicious, check the body length and
Content-Type first. A soft 404 gives itself away as an HTML document on a
path that should return JSON:
curl -s -o /dev/null -w '%{http_code} %{content_type} %{size_download}\n' https://api.example.com/v1/nope
For SPA hosting, compare a known-good path against a garbage path. If both return 200 with the same byte count, the rewrite rule is catching everything and you need a real 404 branch for API prefixes and asset extensions. For APIs, grep logs for 200 responses whose body contains an error key, then fix the handler rather than the monitoring. The status code lookup is a quick way to compare what an endpoint actually sends.
Working examples
curl
# The shape of a 200 matters more than the code. Print the useful parts.
curl -s -o /dev/null \
-w 'status=%{http_code} type=%{content_type} bytes=%{size_download} time=%{time_total}\n' \
https://www.example.com/
# Headers only, without downloading the body:
curl -sI https://www.example.com/
Python (requests)
import requests
resp = requests.get("https://api.example.com/v1/widgets/123", timeout=10)
# 200 alone is not success for an API that reports errors in the body.
resp.raise_for_status() # only catches 4xx/5xx
body = resp.json()
if isinstance(body, dict) and body.get("error"):
raise RuntimeError(f"soft failure behind 200: {body['error']}")
print(resp.status_code, resp.headers.get("Content-Type"), len(resp.content))
Node (fetch)
// Detect soft 404s: a 200 that hands back HTML where JSON was expected.
const res = await fetch("https://api.example.com/v1/widgets/123");
const type = res.headers.get("content-type") ?? "";
console.log(res.status, type, res.headers.get("content-length"));
if (res.ok && !type.includes("application/json")) {
console.warn("200 with unexpected content type - likely an SPA fallback");
}
console.log(await res.text());Reference and tooling
The authoritative list of assigned status codes is theIANA HTTP Status Code Registry. For a searchable copy with the semantics summarised, use theHTTP status code reference on this site. To see exactly what a server is sending, theheader inspector shows the raw status line and response headers, and thecurl builder assembles the request flags for you.