The Google Rich Results Test will happily validate schema markup that Google will never use to surface a rich result. Validation checks syntactic correctness — required fields are present, types are valid, the JSON parses. Eligibility checks something different: whether the markup describes something Google actually wants to render as a rich result, on this page, for this query, at this time.
Most schema audits stop at validation. That's why most clients have schema markup that "validates clean" but produces zero rich results in GSC's Enhancements report. This post is the eight bugs that pass validation and silently block actual rich results, and how to find them.
A Product schema with a price and availability on a page that's a category listing, not a specific product
Google's policy: schema must describe content that is on the page and visible to users. The Rich Results Test passes because the markup is valid. The real Google index, two weeks later, declines to surface the rich result because the content fingerprint doesn't match.
The diagnostic: compare every claim in the schema to what's actually rendered. Every Q&A in FAQPage schema must exist on the page as visible text. Every Product property must reflect what the page is about.
A category page listing 24 products should not have 24 separate Product schemas. It should have an ItemList containing 24 ListItem entries, each linking to the individual product page.
The pattern that fails: a product-listing template that emits a full Product schema (with its own price, availability, reviews) for every item on the listing page. The Rich Results Test sees 24 valid Product schemas and approves them all. Google sees an obvious attempt to claim 24 rich results on a single URL and assigns none.
The fix: ItemList on category pages, Product on individual product pages.
AggregateRating with ratingValue: 4.9, reviewCount: 247 validates fine. If the page does not actually show those 247 reviews (or a link to them), Google won't surface the star ratings in SERPs.
The 2024 policy update tightened this: AggregateRating schema must be accompanied by visible review content on the same page. A page that says "4.9 stars from 247 reviews" in a banner with no underlying review content is treated as misleading schema and the stars are suppressed.
The fix: either show reviews on the page (testimonials, embed Google reviews, etc.) or remove the AggregateRating schema. The AI Visibility Grader flags AggregateRating without visible reviews as a high-priority issue precisely because it's invisible without it.
If the page has a visible breadcrumb saying Home > Products > Audio > Headphones, and the BreadcrumbList schema says Home > Audio > Headphones (skipping a level, or in a different order), Google rejects the schema as a content mismatch.
This sounds obvious but it happens constantly because the visible breadcrumb is rendered by a different system (CMS theme, page builder) than the schema (a plugin, a manually-edited template). The two drift apart over time.
The diagnostic: open the page, count the visible breadcrumb levels, count the schema BreadcrumbList items. They must match exactly.
Some CMS templates emit datePublished and dateModified as new Date() on every page render. Every fetch of the page reports a publish date of "today". Google detects this and stops trusting the dates entirely, which means no "freshness" signal and no "Recently published" SERP treatment.
The fix: datePublished should reflect when the content was originally written. dateModified should reflect actual meaningful updates, not template-level rebuild times. Static-export systems often default to "build time" for both, which is almost as bad — every weekly rebuild ages the published date by a week.
For a blog: parse the post's frontmatter date and use that. The original Recon blog template did exactly this — datePublished comes from MDX frontmatter date, dateModified from updated. A static rebuild doesn't change either.
The Organization schema's logo field must point to a URL the Google crawler can fetch. Common failures:
logo: "https://cdn.example.com/logo.svg" where the CDN blocks Googlebot
logo: "https://example.com/wp-content/uploads/2023/logo.png" where the file has been deleted
logo: "/images/logo.png" (relative URL — must be absolute)
logo: "https://example.com/logo.svg" where the SVG includes JavaScript or external references that Googlebot won't follow
The logo is what populates Google's knowledge panel and AI Overview source citations. A broken logo URL means no logo in the knowledge panel, which materially weakens brand presence in search.
The diagnostic: curl -A "Googlebot" <logo URL> and verify a 200 with a valid image response. If you don't get that, fix the URL before anything else.
JSON-LD inside <script type="application/ld+json"> must be valid JSON. The Rich Results Test catches most syntax errors, but two specific failures slip through:
Unescaped < in string values. If a description includes "for <$100 budgets" the < inside a <script> tag gets parsed as the start of an HTML tag and corrupts the JSON. Escape as <. The Recon JsonLd component does this automatically; manual emission often doesn't.
Trailing commas after the last property. Valid in JavaScript objects, invalid in JSON. The Rich Results Test catches it sometimes; some renderers don't.
The Meta Tag Analyzer flags any JSON-LD that fails to parse. Run it across the top 10 pages of any client site — there will almost always be at least one broken JSON-LD block nobody knew about.
Schema injected by client-side JavaScript after page load is much less reliably picked up by Google than schema in the initial HTML. Googlebot does render JavaScript, but the rendering queue is separate from the indexing queue, and the lag can be days to weeks.
The pattern that fails: a single-page app that injects schema after route navigation. The schema is technically present in the rendered DOM, but the indexing pass that scored the page didn't see it.
The fix: server-render the schema, or use a static-site-generator approach that bakes it into the initial HTML. For Next.js App Router, that means emitting schema from server components (the default), not from client components.
The diagnostic sequence that catches the eight bugs above:
Run the Rich Results Test. Confirm validation passes. (If it doesn't, fix that first.)
Run the Meta Tag Analyzer. Confirms JSON-LD parses without syntax errors.
curl the page with User-Agent: Googlebot. Compare to the rendered page. Schema in the curl output is server-rendered; schema only in the browser DOM is client-rendered.
Spot-check claim alignment. For each schema type on the page, compare every claim (review count, FAQ list, breadcrumb levels) to visible content.
Check the logo URL with curl -A "Googlebot". Verify it returns a valid image.
Check GSC's Enhancements report 14 days after deploy. If rich results don't materialize, one of the above is the culprit.
Adding more schema types in hopes that one will land. Quality over quantity. Two well-formed, claim-accurate schemas earn more rich results than ten misaligned ones.
Using schema generators that emit "best practice" defaults. Generated schema often includes fields that don't match your content. Audit every property.
Treating the Rich Results Test as the source of truth. It validates syntax. GSC's Enhancements report shows what actually surfaced.
Schema claims match visible content, ItemList not multiple Products on category pages, AggregateRating only with visible reviews, BreadcrumbList matches visible breadcrumb, dates reflect real publish/update times not build times, logo URL is fetchable by Googlebot, JSON-LD parses with escaped <, schema is server-rendered not injected client-side.
Eight things. Most sites with "valid" schema fail two or three. Fixing them is the difference between schema that decorates and schema that earns SERP real estate.