How to fix soft 404 errors
A soft 404 is a page that tells a human it does not exist while telling a crawler it does. The body says not found, the server answers 200. Google's crawl documentation describes exactly how this gets caught: “If the content suggests an error for Google Search, an empty page or an error message, Search Console will show a soft 404 error.” The fix is to return a real 404 or 410 status code, or to give the page content worth indexing.
The symptom: your error pages are getting indexed
Search Console lists URLs under “Soft 404” in the Page Indexing report. Or worse, nobody checked Search Console and the symptom shows up in the wild: a search result that leads to a “Sorry, we couldn't find that page” screen, or an AI answer that cites a URL on your domain that has been dead for a year. The page looks like an error to every human who lands on it. To the crawler it looked like a perfectly healthy page, because the server said 200.
Status codes are the contract between your server and every machine that reads your site. A 200 means “here is the content you asked for.” When the content is an error message, the contract is broken. Google's Search Console documentation puts the mismatch in one sentence: the page “returns a user-friendly 'not found' message but not a 404 HTTP response code,” per the Page Indexing report reference. Crawlers read the code first and the words second. If the code lies, the crawler wastes budget on dead URLs, keeps them in the index longer than it should, and trusts your other 200s a little less.
The cause: the server says 200 when it means 404
Three patterns produce almost every soft 404 we see.
- SPA catch-all routes. A single-page app serves
index.htmlfor every path so client-side routing can take over. The router renders a “not found” view for a bad path, but the server already answered 200 before the JavaScript ran. Every misspelled or deleted URL on the domain is now a 200. - Custom error pages without the status code. Someone built a friendly error page, then wired it up as a redirect or a rewrite instead of an error handler. The visitor sees “page not found.” The response header says 200, or 302 to a page that says 200.
- Thin auto-generated pages. Empty category pages, zero-result search pages, placeholder profiles. Nothing on them says “error,” but there is nothing on them at all, and Google classifies an empty page the same way it classifies an error message.
In each case the root cause is the same. The decision about whether a page exists was made in the wrong layer, or never made at all.
The fix: make the status code tell the truth
Decide what each dead URL actually is, then answer with the matching code.
- If the page is gone and nothing replaces it, return
404. If it is gone permanently and you want Google to drop it faster, return410. - If a genuine replacement exists, return a
301redirect to that specific page. Not to the homepage. A redirect to an irrelevant page is just a soft 404 with extra steps, and Google treats it as one. - If the page should exist but is empty, fill it or remove it. A zero-result page either earns its 200 with real content or returns 404.
In an Express app, the error handler goes after every real route, and it sets the code before it sends the friendly page:
// Last middleware: anything unmatched is a real 404. app.use((req, res) => { res.status(404).sendFile("404.html", { root: "public" }); }); // For an SPA, keep the catch-all for real app routes only, // and let unknown paths fall through to the 404 handler.
For a purely static host, most platforms let you define a custom 404 page that keeps the real status code. Use that mechanism, not a rewrite. The friendly error page and the honest status code are not in conflict. You can have both, and you should.
Be honest: a 404 is not a failure
Site owners avoid 404s because the word “error” sounds like something to hide. So they redirect every dead URL to the homepage and call the report clean. That is the dishonest version of this fix, and it does not work. Google documents mass redirects to irrelevant pages as soft 404s too, and visitors who asked for a product page and got your homepage leave. A URL that no longer exists should say so. That is not a defect. It is the one situation where an error code is the correct, honest answer, and machines reward servers that answer honestly.
Verify: check the code, not the page
Your eyes cannot verify this fix, because the visible page looks identical either way. Check the header:
curl -I https://example.com/some-deleted-page HTTP/2 404 ← this line is the whole test
Run that against a URL you know is dead. If the first line says 200, the fix is not live. Then confirm in Search Console: use URL Inspection on a formerly soft-404 URL and watch the Page Indexing report over the following weeks as the “Soft 404” count drains.
Then verify it the way the engines will. Paste your link into our GEO audit or the full Brimm audit and we fetch your 404 behavior directly: we request a URL that cannot exist and read the status code your server actually returns. If it says 200, we flag it. For the wider picture on why crawl-level failures keep sites out of AI answers, start with why isn't my site showing up in AI search, and the rest of the fix library covers the other failures we find most.