How to Fix a 404 Not Found Error
A 404 means the request was valid but the URL points at nothing — the server looked and found no matching resource. The fix depends entirely on whether it's a page or an API call, so here's how to tell them apart and repair each cause.
A 404 Not Found is the most recognizable error on the web — it's the one non-developers know by name. But that familiarity hides how many different problems all surface as the same status code. The server is telling you one precise thing: your request was well-formed and it reached the right place, but there is nothing at the URL you asked for. Everything else — why nothing is there — is the part you have to work out.
What a 404 actually means
A 404 Not Found is an HTTP status code returned when the server can't find any resource matching the requested URL. The request was valid and the server was reached — the path simply points at nothing that exists. It says the target is absent, not that the server failed or that you were denied access.
404 lives in the 4xx family, which HTTP reserves for client errors — problems with the request rather than the server. In practice, a 404 rarely means you did something wrong; it usually means a URL somewhere is stale or a route was never wired up. What makes it worth splitting into two cases is that the fix is completely different depending on whether the 404 came from loading a page or from a background API call. Treat them separately and the cause almost always falls out quickly.
404 on a page or URL
When a whole page shows the browser's or your framework's 404, the resource behind that address can't be located. The usual culprits, in rough order of frequency:
- A broken link or typo — an
<a href>, bookmark, or hand-typed URL points at a path that never existed or was misspelled. Case matters on most servers:/Aboutand/aboutare different resources. - A moved or deleted page — the content used to live at that URL and no longer does. This needs a redirect from the old path to the new one, not just a fix at the link source, because external sites and search engines still point at the old address.
- A missing route in your router — the page exists in your app but you never registered its path, or you registered it with a subtly different pattern (a missing parameter, a wrong segment).
- A trailing-slash or case mismatch —
/blog/postand/blog/post/can resolve to different things depending on server config, and one of them 404s.
The fix for the SPA case is to tell the server to serve index.html for any path it doesn't recognize as a real file, so the JavaScript bundle loads and the client router can render the right view. In Nginx, try_files does exactly this:
server {
root /var/www/app/dist;
location / {
# Try the exact file, then a directory, then fall back to
# index.html so the SPA router handles the path client-side.
try_files $uri $uri/ /index.html;
}
# Real API and asset routes are matched BEFORE the fallback,
# so they still 404 correctly when they should.
location /api/ {
proxy_pass http://localhost:3000;
}
}Most hosts have an equivalent: a _redirects or rewrite rule mapping /* to /index.html on static hosts, or the framework's own catch-all route. Server-rendered frameworks (Next.js, Remix, SvelteKit) mostly avoid this because the server knows every route — but you can still 404 by naming a file or route segment wrong, so the same "does this route actually exist on the server?" check applies.
404 on an API call
When the page loads fine but a fetch or XHR comes back 404, the request reached a server that has no handler for that exact path. The common causes:
- The wrong endpoint path — a typo, a wrong segment, or a plural/singular mismatch (
/uservs/users). - The wrong base URL or environment — the client is pointed at a base URL where the route genuinely doesn't exist, often because an env variable resolved to staging, localhost, or an old domain.
- A missing version prefix — the API lives under
/v1or/api/v2and the client dropped it, so/users/42404s while/v1/users/42works. - An id that doesn't exist —
/orders/9999is a perfectly valid path, but there's no order with that id. This is often a legitimate 404 by design, and the fix is in your code's handling of the missing case, not the URL. - Route registered after a catch-all — if a wildcard or 404 handler is registered before a specific route, the specific route is never reached and always 404s. Order matters.
The fastest way to confirm what actually left the browser is curl — it strips away every layer of client abstraction and shows you the raw request and status:
# -i prints the response status and headers so you see the 404 directly
curl -i https://api.example.com/users/42
# HTTP/1.1 404 Not Found
# content-type: application/json
#
# {"error":"Not Found"}
# Now try the versioned path — a missing prefix is a top cause
curl -i https://api.example.com/v1/users/42
# HTTP/1.1 200 OK <- the route existed all along, under /v1If curl to the corrected path returns 200, you've found it: the client was building the wrong URL. If even the hand-crafted path 404s, the route genuinely isn't registered on that server — check your route definitions and their ordering, or whether you're hitting the environment you think you are. A 404 here often masquerades as a broken feature, when a network-level look shows a simple request going to the wrong place.
How to diagnose a 404 in four checks
Whichever kind of 404 you're facing, the same short sequence isolates it:
- Read the exact URL in the Network tab. Open DevTools, find the red request, and copy the full URL character for character. Half of all 404s are visible right here — a typo, a missing prefix, or a base URL you didn't expect.
- Confirm the route exists on the server. Does a handler or file actually answer that path? Check your router definitions and their order.
- Check env and base URLs. Verify the environment variable that builds the base URL resolved to the host you intended, not staging or localhost.
- Check routing and rewrite config. For pages, look at your SPA fallback or
try_files; for moved content, confirm the redirect exists. A missingindex.htmlfallback is the whole story for refresh-only 404s.
404 vs 403, and soft-404s
It's easy to blur 404 with its neighbours, but the distinction changes where you look for the fix:
- 404 Not Found — the server can't find the resource. Nothing exists at that URL, as far as it can tell.
- 403 Forbidden — the resource exists, but you're not authorized to access it, even if you're logged in. This is a permissions problem, not a routing one. Some servers intentionally return 404 instead of 403 so they don't reveal that a protected resource exists.
- Soft-404 — the worst of both: the server returns a
200 OKstatus but the page content is actually an error or "not found" message. This confuses browsers, search engines, and monitoring, because the status says success while the body says failure. If a page looks like a 404 but the Network tab shows 200, you have a soft-404, and the fix is to return a real404status.
For a broader map of how 404 sits among the other status families — 3xx redirects, other 4xx client errors, 5xx server errors — see our HTTP status codes explained reference.
Good 404 UX
Some 404s are unavoidable — links rot, people mistype, old URLs get shared forever. What you control is what happens next:
- Ship a custom 404 page that keeps the site's design, explains what happened in plain language, and offers a way forward: a search box, links to popular pages, and a route home. A dead end that dumps the user out of your app is a lost visitor.
- Redirect moved content with a
301(permanent) redirect from every old URL to its new home, so bookmarks and search rankings survive the move instead of decaying into 404s. - Return the honest status. Your custom 404 page should still respond with a real
404status code, not a200— that's what keeps crawlers and monitoring accurate and avoids the soft-404 trap above.
Install the free BugMojo extension and capture the exact request — the URL that 404'd and the page that linked to it — so you fix the stale link at the source instead of guessing which one it was.
Install the free extensionFrequently asked questions
Frequently asked questions
Sources
- 404 Not Found — MDN reference: the server cannot find the requested resource; the URL is not recognized — MDN Web Docs (2026)
- HTTP response status codes — MDN reference: the full list of status codes and their categories — MDN Web Docs (2026)
- RFC 9110: HTTP Semantics — the specification defining 404 and the rest of HTTP status semantics — IETF RFC 9110 (2022)
- 403 Forbidden — MDN reference: the server understood the request but refuses to authorize it — MDN Web Docs (2026)
Get bug-tracking insights, weekly.
Engineering deep-dives, QA playbooks, and honest tool comparisons. No spam — unsubscribe in one click.

