The deployment finished. The health check passed. The dashboard was green.
200 OKExcellent.
I opened the website.
It contained an error page.
Technically, the server had succeeded. Emotionally, nobody else had.
This is the moment when you learn that 200 OK does not mean your application is OK.
Status codes describe the HTTP response
HTTP/1.1 200 OK
Content-Type: text/htmlCommon families are:
2xx success
3xx redirection
4xx request or access problems
5xx server problemsUseful, but a status code does not read your HTML and decide whether your business logic is happy.
A page can say 404 while HTTP says 200
The server may return 200 while the body contains:
<h1>404 - Page Not Found</h1>Humans see 404. Machines see 200. A missing page that behaves this way is commonly called a soft 404.
Search engines may try to detect it. A simple uptime monitor may just celebrate the 200.
Single-page apps make this easy
SPAs often return the same index.html for many routes and let client-side JavaScript decide what to display.
If the file does not exist:
return index.htmlVisit a nonsense URL and the server successfully returns index.html with status 200. The app later renders “Page not found.” Every layer followed its instructions and the combined result is still misleading.
CDNs, Workers and proxies can add another layer
Browser
↓
CDN
↓
Worker / proxy
↓
Origin
↓
ApplicationAny layer can cache, redirect, rewrite or replace an error page. An origin may return 500, a proxy may replace it with friendly HTML, and that proxy may accidentally return the replacement as 200.
Your uptime monitor says everything is wonderful. Your users are reading a beautifully styled explanation of why it is not.
A quick status-code map
- 200: response succeeded, not necessarily the expected content.
- 301: permanent redirect.
- 302: temporary redirect.
- 304: cached representation is still valid.
- 400: bad request.
- 401: authentication required or failed.
- 403: understood, but refused.
- 404: resource not found.
- 429: too many requests.
- 500: internal server error.
- 502: gateway received a bad upstream response.
- 503: service temporarily unavailable.
A health check that only tests 200 can lie
const response = await fetch(url);
if (response.status === 200) {
console.log("Healthy");
}This proves one thing: the URL returned 200.
A better production check can verify status, content type, an expected application marker, the absence of challenge/error pages and a structured health response from critical APIs.
Testing the real production hostname also matters. A provider's deployment URL being healthy does not prove the custom domain serves the same build.
Status codes matter for SEO too
Use an appropriate redirect when content permanently moves and a real 404 or 410 when it is gone. Do not wrap every path in 200 and make crawlers guess your intentions.
The final lesson
Status codes are important metadata about an HTTP transaction. They are not mind readers.
200 OK means the server successfully gave you something.
It does not promise that the database is alive, JavaScript loaded, authentication works, the correct build is deployed or users are having a lovely afternoon.
So check the status code.
Then check the content.
Sometimes the most dangerous error page is the one confidently wearing a green 200 OK badge.