Is It Down, or Is It Just Me? How to Actually Diagnose an Outage
In a single 24-hour window this week, US search saw spikes for t mobile outages, american airlines outage, american airlines system down, and a steady background of Downdetector traffic. It happens most weeks.
The instinct is to search "is X down" and trust the first result. That is often wrong, and it is worth knowing why — plus the sequence that actually answers the question.
Why crowd-sourced outage sites mislead
Sites like Downdetector work by counting user reports and comparing against a baseline. That is genuinely useful and has two structural biases worth understanding.
They are lagging. Reports require humans to notice, care, and submit. A spike appears several minutes after an incident begins, and stays elevated well after resolution because people keep reporting from stale pages.
They conflate different failures. "American Airlines is down" aggregates the website, the mobile app, check-in kiosks, and the reservation backend. Those are separate systems. A spike tells you something is wrong, not what.
They have a popularity floor. A service with a small user base can be entirely down and never register a visible spike.
So: useful as corroboration, not as diagnosis.
The diagnostic sequence
Work outward from your own machine. Each step eliminates a layer.
1. Is it DNS?
Disproportionately often, yes.
# Does the name resolve at all?
dig example.com +short
# Compare your resolver against a public one —
# a difference means local DNS or a stale cache
dig @1.1.1.1 example.com +short
dig @8.8.8.8 example.com +short
If the public resolver answers and yours does not, the outage is your network, your ISP, or your local cache — not the service.
# Flush the local cache
sudo dscacheutil -flushcache # macOS
ipconfig /flushdns # Windows
sudo systemd-resolve --flush-caches # Linux
2. Does it respond at all?
# Status line and timing only
curl -sS -o /dev/null -w "%{http_code} dns:%{time_namelookup}s connect:%{time_connect}s total:%{time_total}s\n" https://example.com
That one line separates several failure modes:
- No output, hangs — packets are not getting there; network or firewall
- TLS error — certificate expired or a middlebox intercepting
000— connection failed before HTTP5xx— you reached the server and it is broken200but slow — degraded, not down
A 5xx is meaningfully different from a timeout: it means the infrastructure is reachable and the application is failing. That distinction usually tells you which team owns the problem.
3. Is it just you?
# Are you reaching the same edge as everyone else?
curl -sI https://example.com | grep -iE "server|cf-ray|x-served-by|x-cache"
CDN headers reveal which edge node served you. Outages are frequently regional — one CDN point of presence is broken and everyone else is fine. If a colleague in another city gets a different cf-ray prefix and a working response, you have found the shape of the problem.
4. Check the official status page
Almost every serious service publishes one, and many expose JSON:
curl -s https://www.githubstatus.com/api/v2/status.json
Two cautions. Status pages are frequently manually updated, so they lag reality — a service can be visibly broken while the page is green. And some status pages are hosted on the same infrastructure as the service, which is an obvious flaw that has bitten several large providers.
5. Read the actual response body
This is the step people skip, and it is often the one that answers the question.
curl -s https://api.example.com/v1/users | head -c 500
If you are expecting JSON and getting HTML, you have your answer immediately — you hit an error page, a login redirect, or a proxy notice rather than the API. In application code this surfaces as:
Unexpected token < in JSON at position 0
That < is the opening of <!DOCTYPE html>. The JSON parser is doing its job and reporting a networking problem. Our guide to JSON errors covers this case in detail — it is one of the most commonly misdiagnosed errors in web development.
Handling it properly in code
Most client code assumes the happy path and produces a confusing parse error when the response is not JSON. Check first:
async function fetchJson(url) {
const res = await fetch(url);
// Status before parsing — a 503 body is not your data
if (!res.ok) {
const body = await res.text();
throw new Error(`HTTP ${res.status}: ${body.slice(0, 200)}`);
}
// Content-type before parsing — catches the HTML-error-page case
const contentType = res.headers.get("content-type") ?? "";
if (!contentType.includes("application/json")) {
const body = await res.text();
throw new Error(`Expected JSON, got ${contentType}: ${body.slice(0, 200)}`);
}
return res.json();
}
Those two guards convert Unexpected token < — which tells you nothing — into an error naming the status code and showing the actual body. During an incident that difference is worth a great deal.
When it is genuinely down
Once you have established the service is broken and it is not your side:
Stop retrying aggressively. A tight retry loop from every client turns a partial outage into a total one. Use exponential backoff with jitter, and a circuit breaker that stops calling entirely after repeated failures.
Fail visibly, not silently. A user who is told "our payment provider is unavailable, your cart is saved" is far better served than one who sees a spinner.
Capture the evidence now. Response headers, request IDs, timestamps, and the raw body. Support will ask, and the data disappears once the incident resolves.
Check your own dependencies for the same fault. If a shared provider is down, several of your services are probably affected. Correlated failure is the norm, not the exception.
Reading the logs
Incident debugging means reading structured log output, and modern loggers — Pino, Winston, Bunyan, structlog — emit one JSON object per line. Perfect for machines, unreadable at 2am.
Paste a line into a JSON formatter and it becomes a legible event immediately. Ours runs entirely in your browser, which matters here specifically: log lines from a production incident routinely contain session tokens, internal IDs, and customer email addresses. That data should not be uploaded to a third party while you are debugging.