404 Not Found
Client Error
The server cannot find a current representation for the requested resource. 404 makes no claim about whether the resource ever existed or whether it might exist in the future. It is intentionally non-committal. Search engines treat 404 as a soft signal: the URL may be removed from the index over multiple crawl cycles, but Google specifically does not transfer any ranking signals from 404 pages. If a resource is permanently gone and you want a stronger signal, return 410 instead.
When does this happen?
Return 404 when the requested URL does not map to any resource the server can serve. This covers typos in the URL, pages that have been deleted without a redirect, mismatched routing rules, or attempts to access org-scoped resources from the wrong tenant. The response body should be a helpful 404 page or, for APIs, a JSON error with a code clients can react to programmatically. Two pitfalls dominate: first, returning 200 with a "page not found" body. Google calls these soft 404s and they pollute the index; always return the correct HTTP status. Second, returning 404 for resources that exist but the caller cannot access. For org-scoped APIs this is a deliberate security trade-off (do not leak existence) but for public pages it can hide content that should be discoverable. Use a custom 404 page with site search, navigation, and helpful links rather than a bare error message.
Common causes
- Typo in the URL. Capital letters, extra slashes, or misspelled paths.
- Resource deleted from the database without a redirect being created in the routing layer.
- Broken link from an external site or internal navigation pointing at an outdated URL.
- URL structure changed during a CMS or framework migration without 301 redirects mapping old paths to new ones.
- Routing misconfiguration. A missing route definition, a typo in a regex, or middleware short-circuiting before reaching the handler.
- Org-scoped resource accessed from the wrong tenant. Many APIs return 404 deliberately rather than leak existence with 403.
- Static asset removed from the CDN bucket but referenced by old HTML still in users' browser caches.
- Server-side rendering failure that silently maps to 404 instead of 500.
- Trailing-slash mismatch. /about and /about/ treated as different URLs by strict routers.
How to fix it
- Check the URL for typos and capitalization. Many web servers are case-sensitive on Linux but not macOS, so dev/prod mismatches are common.
- Set up 301 redirects from removed or moved URLs to their new locations. Never leave a 404 in place if you have an obvious destination.
- Build a custom 404 page with site search, navigation, and recent content so users can find what they were after.
- Audit your site for broken links periodically. Tools that crawl your own pages and flag 404s catch problems before users do.
- Submit a fresh sitemap to Search Console so old URLs are removed from the index quickly.
- If 404 is appearing on URLs that should work, check your router/middleware order. Middleware that responds early can short-circuit valid routes.
- Confirm the URL casing matches the file system. Staging-prod-mismatch on case-sensitive filesystems is a classic deploy bug.
- For org-scoped APIs, return 404 (not 403) when a resource belongs to another tenant. This prevents existence-leak attacks.
- Never return 200 with a not-found page body. Google's soft 404 detector will penalize the URL and pollute the index.
Real-world examples
- User clicks a five-year-old link to /blog/2019/announcement that was deleted last month with no redirect.
- Server returns 404 with the custom not-found page. Search engines drop the URL after a few crawl cycles.
- Developer types /api/v1/use rs (with a space) in a browser when they meant /api/v1/users.
- Server returns 404. DevTools shows the request as failing and the developer corrects the typo.
- User from organization A tries to GET /v1/projects/{id} where the project belongs to organization B.
- Server returns 404 with {"error":"not_found"} rather than 403 to avoid leaking that the project exists.
- CMS migration changed /node/123 to /blog/welcome but no redirect was set up.
- Crawlers hitting /node/123 receive 404. Backlinks to the old URL no longer transfer link equity and the new URL has to earn ranking from scratch.
- Single-page app routing returns 200 with a "page not found" component for unknown client-side routes.
- Browser shows a not-found page but the HTTP status is 200. Google flags the URL as a soft 404 and may remove it from the index.
- Image referenced in an article was deleted from the CDN bucket but the article still has the old <img> tag.
- Browser requests the image, gets 404, and shows a broken-image icon. The page itself is still 200.
Debugging
- Run curl -I https://example.com/path and confirm the response is HTTP/1.1 404 Not Found. Not 200.
- Inspect the response body. Many sites return 200 with a not-found template, which Google treats as a soft 404. Check the Status-Line, not the body.
- Use a site crawler against your own domain to find all 404s. They often cluster around deleted content or recent migrations.
- Cross-reference Search Console's Coverage report with your sitemap. URLs flagged as Not Found there are public 404s worth fixing.
- Check case sensitivity. Try the same URL with different capitalization and see whether the 404 disappears. If it does, your routing is case-sensitive and links elsewhere are wrong.
How it differs from related codes
HTTP 410
410 is a stronger "this is gone permanently" signal than 404. Search engines de-index 410 URLs faster. Use 410 when you have deliberately removed content and have no replacement.
HTTP 301
301 redirects to a new URL and preserves link equity. 404 leaves the user (and search engine) with a dead end. If you have a relevant destination, redirect instead of 404.
HTTP 403
403 says "this exists but you cannot access it." 404 says "there is nothing here." Many APIs deliberately return 404 instead of 403 for cross-tenant access to avoid leaking existence.
Related status codes
See HTTP 404 in your redirect chains?