"Soft 404" in Search Console
Your server says 200 and your page says the content is gone. Google believes the page, not the status code, and refuses to index either.
This URL is not indexed and it should be. Something is in the way.
Is it still happening?
Paste the URL Search Console flagged. We fetch it, read its status, title, heading, and how much text it actually contains, and separately request a URL we invent on the same host to see whether your server can return a 404 at all.
Whether the status code contradicts the page content, and whether your server returns 404 for URLs that do not exist.
Google also classifies a page as a soft 404 when the content is too thin to be worth indexing, which is a judgement about substance rather than a signal we can measure. A clean result here means the mechanics are right, not that the page is necessarily substantial enough.
What this error actually means.
Google requested this URL, got a 200 OK, and then decided the response was not a real page. Either it announced itself as missing, or there was too little on it to be worth indexing.
The mismatch is the entire problem. A status code is a machine-readable claim about whether content exists, and a soft 404 is a page making that claim in one place and contradicting it in another. Google resolves the contradiction by trusting what it can read.
This is one of the few rows where the cause is often site-wide rather than page-specific. A single-page-application router or a catch-all route that renders an error view without changing the status will produce a soft 404 for every dead URL on the site at once.
6 things that produce this error.
Ordered by how often they turn out to be the cause, not by how obvious they look.
An error page served with a 200 status
The page says "not found" and the server says everything is fine. Common in single-page applications, where routing happens in the browser after a 200 has already been sent, and in frameworks where a custom error template was wired up without changing the status code.
HTTP/2 200 <- what the server said
<h1>Page not found</h1> <- what the page saidA catch-all route that renders something for every path
Any unmatched URL returns the app shell or the homepage with a 200. Google can invent a URL, receive a valid response, and conclude that your site never signals a missing page. This is the version worth testing for first, because it affects every dead URL you have.
An empty listing page
A category with no products, a tag with no posts, a search results page with no matches, a filter combination that returns nothing. The page is technically correct and has nothing on it, so Google reads it as an empty shell rather than content.
Content that requires JavaScript that failed or was blocked
The HTML arrives nearly empty and the content is fetched client-side. If the script errors, times out, or its bundle is blocked in robots.txt, Google renders a page with no content and classifies it accordingly. The page looks fine in your browser because your browser succeeded.
A page behind a paywall or a login that renders a stub
A 200 that shows a prompt instead of content. Without structured markup describing the paywall, Google sees a page whose entire body is an invitation to log in.
A product or listing that expired without a redirect
The item is gone, the template still renders, and the page now consists of a heading and an apology. Common on e-commerce and job boards, where the URL should either return 410 or redirect to a genuine replacement.
How to clear it.
Test whether your site ever returns a 404 at all
Request a URL you are certain does not exist. If it returns 200, that is the root cause and it affects every dead URL on the site, not just the one Google flagged. Fix it once and the whole report row usually clears.
curl -sI https://example.com/this-page-cannot-possibly-exist-9f2a | head -1
# Want: HTTP/2 404
# Bad: HTTP/2 200Return the status that matches the content
A page that says content is missing must return 404, or 410 if the removal is permanent and you want it dropped faster. Keep the friendly error design; only the status line needs to change. In a single-page application this means the server has to know which routes exist rather than deferring every decision to the client.
// Next.js App Router
import { notFound } from 'next/navigation';
const post = await getPost(slug);
if (!post) notFound(); // renders not-found.tsx with a real 404Give empty listings something, or take them out of the index
An empty category should either show related content and stay indexable, or return 404 and stop being advertised. The one thing not to do is serve an empty 200 and keep it in the sitemap, which is what produces this row on most e-commerce sites.
Redirect expired content to a real successor
A sold-out product with a natural replacement should 301 to it. One with no replacement should return 410. Redirecting everything to the homepage instead is treated as a soft 404 of its own, so it swaps one row of this report for another.
Next to check.
LintPage rules covering this: thin-content, content-to-html-ratio
Questions, answered.
What is the difference between a 404 and a soft 404?
Should I use 404 or 410?
Why is my empty category page reported as a soft 404?
Does a soft 404 hurt the rest of my site?
Can a JavaScript-rendered page cause this?
Catch this one before Search Console does.
Search Console tells you weeks after the fact. LintPage runs 60 checks against a URL in about 30 seconds. Free, no signup.
run a full scan →