Your JSON-LD passes every validator you throw at it. Green checkmarks across the board. But when you check Google Search Console, nothing. No rich results, no enhancements, no sign that Google even noticed the markup.
This is the most frustrating kind of technical SEO problem because there's no error message to chase. The code is valid. Google just decided to ignore it. After auditing schema across dozens of client websites, I can tell you the cause is almost always the same handful of structural mistakes that validators aren't designed to catch.
Validators check syntax, not logic
Here's the thing most developers don't realize about Google's Rich Results Test and Schema.org validators: they check whether your JSON-LD is well-formed. They confirm the syntax is correct, the types exist, and the properties match. What they don't check is whether the markup makes sense as a whole.
Think of it like spell-check on a contract. Every word is spelled correctly, but the contract contradicts itself in three places and references a clause that doesn't exist. Spell-check passes. The contract is still broken.
That gap between "valid code" and "useful code" is where rich results go to die. Google's systems need to build a coherent knowledge graph from your markup. If the pieces conflict with each other, Google doesn't throw an error. It just moves on.
Duplicate Organization entities confuse Google
This is the single most common problem I find. A site has two, sometimes three, separate Organization entities scattered across its pages.
How it happens: the developer adds an Organization block to the site header template. Then a WordPress SEO plugin injects its own Organization block. Then someone manually adds another one on the About page. Each block defines the same company but with slightly different details: a different logo URL here, a slightly different business name there, an extra social profile link on one but not the others.
Google now sees three "sources of truth" for who this organization is. None of them match exactly. So Google trusts none of them.
The fix is straightforward. Define your Organization exactly once, give it a clear @id (like https://yoursite.com/#organization), and have every other reference point back to that single @id. One source of truth, many references. That's how schema is supposed to work.
Conflicting property values across blocks
Even without outright duplication, conflicting values between related schema blocks will quietly break things.
I've seen a site where the LocalBusiness schema listed the business hours as 9 to 5, Monday through Friday. The OpeningHoursSpecification on the Contact page said 8 to 6. The Google Business Profile said 9 to 6. Three different answers to the same question.
Google's response to conflicting signals is predictable: distrust. If your own site can't agree on your business hours, why should Google confidently display them in a rich result?
This extends to everything: phone numbers, addresses, URLs, price ranges, review counts. Every property that appears in more than one schema block needs to match exactly. Not "close enough." Exactly.
Run a simple grep across your codebase for key properties like telephone, address, openingHours, and priceRange. If the same property appears with different values in different blocks, you've found your problem.
Broken @id references don't resolve
The @id property is how JSON-LD creates internal links between entities. Your WebPage references your Organization. Your Article references its author. Your BreadcrumbList references its parent pages.
When an @id reference points to an entity that doesn't exist, or that exists with a different @id than expected, the reference breaks silently. The validator doesn't flag it because the syntax is fine. But Google can't follow the link, so it treats the entities as disconnected fragments instead of a coherent graph.
Here's a real example. A site's Article schema referenced the author with "author": {"@id": "https://example.com/#author-john"}. But the Person entity on the team page used "@id": "https://example.com/team/john". Two different identifiers for the same person. The reference never resolves.
The discipline here is simple but requires attention: every @id you reference must match an @id you define somewhere else on the site, character for character. I keep a spreadsheet of all @id values for any site with more than a handful of schema types. It sounds tedious. It prevents exactly this class of bug.
Want a website that turns visitors into customers, not just compliments?
Book a 15-min introEmpty required fields fail quietly
Schema.org marks certain properties as "expected" or "required" for specific rich result types. Google's documentation goes further, specifying which fields are required versus recommended for each rich result type.
When a required field is present but empty, validators sometimes pass it because the property exists. Google's systems see an empty value and skip the entire entity.
The usual culprits:
- An
imageproperty that points to an empty string or a broken URL. - A
datePublishedfield set to an empty string instead of an ISO 8601 date. - A
nameproperty left as placeholder text like "Your Business Name Here." - An
authorobject with anameproperty that's an empty string.
These are easy to spot once you know to look for them. Open your page source, find the JSON-LD block, and read every value. If any value is empty, placeholder text, or a URL that 404s, fix it.
Too many schema types with too little substance
There's a temptation, especially with plugins that auto-generate schema, to mark up everything. Every page gets Article, Organization, BreadcrumbList, WebSite, WebPage, and sometimes FAQPage and HowTo thrown in for good measure.
More schema types are not better. Each type you add is a commitment to provide complete, accurate, consistent data for that type. If your FAQPage schema contains one question with a two-word answer, Google isn't going to reward that with a rich result. If your HowTo schema has steps like "Step 1: Get started," you're wasting markup.
Only implement schema types where you have genuine, complete content to back them up. A clean implementation of two types beats a sloppy implementation of eight.
The 10-minute manual check that catches what validators miss
Here's the audit I run on every client site before I consider the schema done. It takes about ten minutes and catches problems that no automated tool will flag.
Count your entities. Search the entire codebase for
@type. List every unique entity type and count how many times each appears. If Organization appears more than once, that's your first fix.Map your @id references. List every
@idyou define and every@idyou reference. Make sure every reference has a matching definition. If something is referenced but never defined, the link is broken.Check value consistency. Pick five key properties: business name, phone number, address, URL, and logo. Search for each one across all schema blocks. If any value differs between blocks, reconcile them.
Read every value. Open the rendered JSON-LD on three to five key pages. Read each property value. Flag anything empty, placeholder, or obviously wrong.
Test in Google's Rich Results Test. Not just for green checkmarks, but read the parsed output. Does the preview match what you expect? If it looks wrong in the preview, it'll look wrong in search results.
Cross-reference with Search Console. Go to the Enhancements section. If Google has found problems with your schema, they'll show up here, sometimes weeks after deployment.
This manual pass is not glamorous work. It's the kind of thing that's easy to skip when a validator already gave you the green light. But it's the difference between schema that validates and schema that actually earns rich results.
Why this matters for your business
Rich results aren't just vanity metrics. A proper rich result can double the visual footprint of your listing in search results. Review stars in a product listing measurably increase click-through rates. Event schema gets your events into Google's event carousel.
When these features work, they compound. When they silently fail, your business loses out on high-intent search traffic because searchers pass over your listing for a competitor's richer, more detailed snippet.
The irony is that the fixes are usually small. Twenty minutes of cleanup, not a complete rebuild. The hard part is knowing where to look, because the automated tools won't tell you.
So before you assume your schema is working because a validator passed it, pull up your JSON-LD, read it like a human, and ask whether it tells a coherent, consistent story about your business. If it doesn't, Google noticed before you did. That's why your rich results aren't showing.