ByteScope

404

How to fix HTTP 404 Not Found

4xx client errorIETF standardRFC 9110

The server understood the request and has nothing to serve at that path — which on a modern stack is far more often a routing or deployment mistake than a dead link.

Why you are seeing 404, and what to do about it

The same three digits are three different problems depending on which side of the request you are on. Read the block that describes you.

Reproduce 404 with curl

Run this against the URL that failed. It prints the status without the error page, so you can see what the server said rather than what the browser rendered.

curl
curl -sS -o /dev/null -L -w '%{http_code} %{num_redirects} %{url_effective}\n' https://example.com/no-such-page

`-sS` drops the progress meter but keeps error messages, `-o /dev/null` throws the error page body away, `-L` follows any `Location` headers, and `-w` prints the final status, how many redirects were followed, and the URL that produced that status. The last field is the point of the command: curl documents `%{url_effective}` as most meaningful once you have asked it to follow redirects, and a 404 at the end of a redirect chain is a different bug from a 404 on the URL you typed — it means a rewrite sent you somewhere that does not exist. A `%{num_redirects}` above zero on a URL you expected to be direct is the tell. To find out whether the edge or the origin produced the 404, run the request twice: once normally, and once with `--resolve example.com:443:203.0.113.10`, which makes curl connect to the address you name while still sending the original host name and SNI. Two different answers mean the edge is serving something the origin is not, which for this code is often a cached 404.

What 404 actually means

RFC 9110 §15.5.5 defines 404 as the origin server not finding a current representation for the target resource, or not being willing to disclose that one exists. Both halves are load-bearing. The first means 404 is about this URL at this moment and says nothing about whether the resource ever existed or ever will — the same section points at 410 (Gone) as the better answer when the server knows the condition is permanent. The second is why 404 and 403 overlap: §15.5.4 explicitly allows an origin server that wants to hide the existence of a forbidden resource to answer 404 instead, so a 404 on a URL you are certain exists can be an access decision wearing a disguise. One more property catches people mid-incident. 404 is one of the status codes RFC 9110 §15.1 lists as heuristically cacheable, which means a proxy or CDN may cache it with no explicit `Cache-Control` at all, so a URL that 404s during a bad deploy can keep 404ing after the deploy is fixed, until the stored response expires or somebody purges it. And 404 carries no opinion about the method: a POST to a path that only accepts GET is 405, not 404, and a framework that answers 404 there is choosing not to tell you which half was wrong.

Codes 404 gets mistaken for

Confused withHow to tell them apart
403403 says the server understood and refuses; 404 says it has nothing there. RFC 9110 §15.5.4 blurs the two deliberately — an origin server that does not want to admit a forbidden resource exists is explicitly permitted to answer 404 instead. So a 404 on a URL you know exists is worth retrying with credentials before you go hunting for a routing bug, because object storage buckets and private repositories do exactly this.
410410 (Gone) is the answer when the server knows the resource is permanently finished, and RFC 9110 says it is preferred over 404 in that case. The difference is a signal to machines rather than to people: a 404 invites retries, while a 410 tells an indexer to stop asking. If you are deliberately retiring content, 410 is the more truthful code and the faster one to get out of a search index.
405405 (Method Not Allowed) means the path exists but not for the verb you used, and RFC 9110 requires the response to carry an `Allow` header listing the methods that do work. A framework that answers 404 for a POST to a GET-only route is permitted to, but it is hiding the useful half of the answer — so check the method before you start doubting the path.
soft 404A soft 404 is a page whose body apologises for being missing while the status line says 200. Nothing in HTTP forbids it, but search engines then index an error page as content, and scripts see a success status and parse the apology as data. If a page you know is missing does not produce a 404 under curl, that mismatch is itself the bug.
nginxnginx produces 404 from more places than a missing file. A `try_files` chain ending in `=404` returns one deliberately; a request whose `Host` matches no `server_name` lands on the default server, which is often a stub with an empty root; and an `alias` that lost its trailing slash builds a filesystem path one directory short. The error log records the path it actually tried, which is the quickest way to tell the three apart.
Reason phrase
Not Found
Class
4xx client error
Defined by
RFC 9110
Standard
IETF standard

Tools on this site

All of these run in your browser — nothing is uploaded.

Related status codes

Codes people usually end up reading in the same session as 404.

Frequently asked questions

How do I find out which server produced this status code?

Read the response headers rather than the page. curl -sS -o /dev/null -D - https://example.com/path prints them without the body, and server, via and cf-ray between them name the layer that answered. A cf-ray value means Cloudflare handled the response and is the id their support will ask for. To take the edge out of the picture entirely, repeat the request with --resolve example.com:443:203.0.113.10, which connects to the origin address you name while still sending the original host name and SNI — if the answer changes, the edge and the origin disagree.

Does the reason phrase after the number matter?

No, and you should never branch on it. RFC 9112 tells clients to ignore the reason phrase, servers are free to change it, and HTTP/2 and HTTP/3 do not carry one at all — so 404 Not Found over HTTP/1.1 arrives as a bare 404 over HTTP/2. The phrases on this site are the registered ones because they are what people search for and what appears in an HTTP/1.1 log, not because any software depends on them.

Should I retry a request that failed with this code?

Retry 5xx and 429; do not retry 4xx, because nothing about the request will be different next time. If the response carries Retry-After, honour it — RFC 9110 defines it for exactly this, and it may be either a number of seconds or a date. Otherwise use exponential backoff with jitter and a hard cap, and only for idempotent methods: a retried POST can charge a card twice. A retry storm against a server that is already failing is how a brief incident becomes a long one.

Can I make my server return a different status code?

Yes, and the only rule that matters is that the code has to be true. Anything that reads your responses automatically — search engines, monitoring, caches, client retry logic — makes decisions from the number and never from the page. Serving an error page with 200 hides the failure from your own alerting; serving 200 for a missing page gets the error indexed as content; returning 500 for a request that was simply malformed sends whoever is on call to the wrong half of the stack.

Still stuck on 404? browse every status code in the reference — or go back up to the block written for your side of the stack.