An @id is a pointer, not a definition
An audit reports that several of your pages have incomplete Organization markup. You open one and the Organization is right there — name, URL, logo, all of it. The blocks the tool is complaining about are not incomplete entities. They are references to that one.
What an @id actually does
In JSON-LD, two nodes that share an @id are one node. That is the
whole point of the identifier, and it is what makes the common @graph pattern work:
define your company once, then point at it from everywhere else.
The pointer looks like this, and it is complete as written:
"publisher": {
"@type": "Organization",
"@id": "https://example.com/#organization"
}
It carries no properties by design. Nobody forgot anything. And because this is what the most widely used SEO plugins and CMS platforms emit by default, a check that reads each stub as its own half-finished entity will fire on an enormous share of the web — including sites whose structured data is exactly right.
The false positive, reproduced on purpose
This one was not found on somebody's site and guessed at. It was reproduced with a controlled
input: a graph that defines an Organization with name, URL and logo, and also
references it by a typed @id. The result was a finding across several pages
saying the Organization markup was incomplete. Nothing was incomplete. The reference was being
counted as a second, worse copy of the thing it pointed at.
If your report says this about a site using a mainstream plugin, check the graph before you touch anything. The stub is not the error; reading it as a definition is.
The real problem underneath, with the opposite fix
Here is why this is worth more than "your tool was wrong". There is a genuine defect that looks identical from the outside, and it is common.
Structured data is read one page at a time. A search engine parsing your
product page does not go and fetch your homepage to resolve an identifier. So if every block of a
type on a page is a bare @id reference, and nothing on that page says what
the identifier refers to, the reference resolves to nothing.
And "add the missing properties" is precisely the wrong instruction, because it misdescribes what happened. Nobody forgot a property. Somebody wrote a reference, deliberately, believing the definition exists somewhere — which it may well do, on a different page, where it cannot help. Telling them to add a name to each stub asks them to duplicate a definition they think they already have.
The two repairs that are actually available:
- Define the entity on every page that references it. This is what plugins do when configured properly, and it is why their output repeats the Organization block everywhere.
- Remove the stub. If you are not going to define it, the pointer is doing nothing for you.
Why nothing catches this
A dangling @id produces neither a rich result nor an error, which
is the most useful sentence on this page.
- A JSON-LD validator sees syntactically valid JSON-LD with a valid identifier, and passes it.
- A rich-results test finds no eligible entity and reports that nothing was detected — which reads like "you have no markup" rather than "you have a pointer to nowhere", and sends you off to add markup you already wrote.
- Your CMS renders exactly what you configured.
It is a failure of resolution, not of syntax, and syntax is what most tooling checks.
What a tool can honestly say about it
Worth stating because it bounds the finding. A crawler reads each page's markup on its own, exactly as a search engine does. So it can tell you the target is absent here. It cannot tell you the target is absent everywhere, because it is not resolving your graph across your whole site — and neither is the search engine, which is the entire reason this matters.
Checking your own markup in five minutes
- View source on a page that was flagged and search for the identifier from the finding. If it appears twice — once as a definition with properties, once as a reference — your markup is fine and the finding is wrong.
- If it appears only as a reference, the page genuinely defines nothing. That is the real version of this problem.
- Check the type matches. A stub typed
Organizationpointing at a node defined as something else is a third failure, and a quieter one. - Check the identifier is stable. An
@idthat changes between pages defeats the purpose — the nodes stop being one node.
When this does not matter
Two cases where a bare reference is fine as it stands:
- The definition is on the same page, further down the graph. Order does not matter within a document.
- The entity is not one you are seeking a rich result for. A pointer that resolves to nothing costs you an entity signal, not a search feature, and if the block was aspirational rather than load-bearing you can simply delete it.
The fixes that make it worse
- Adding a name to every stub. You now have several partial definitions of one entity instead of one good one, which is worse than either the pointer or the definition alone.
- Deleting the
@graph. The graph is not the problem and it is the structure that makes references work at all. - Pointing the
@idat a page URL. An identifier is not a link. It does not get fetched, and a URL that happens to exist does not make the node resolve.
How to clear this finding without improving anything
Delete the reference blocks. The finding goes away, and so does any chance of the entity being understood — you have removed the evidence of an intention rather than completing it. Worth knowing, because "it went green" and "it got better" are different outcomes and only one of them is visible in a report.
Where this sits in an audit
The registered check is schema.incomplete, which covers incomplete structured data
in the structured data area. For the other ways JSON-LD goes wrong — blocks that do not parse,
markup contradicting the visible page, required properties genuinely missing — see
how to fix structured data errors →.
And for the general habit this page is an instance of — a finding whose own advice does not fit the case it fired on — see a caveat is not a gate →.
Common questions
What does @id mean in JSON-LD?
It identifies a node. Two blocks sharing an @id are the same node, which is what lets you define an entity once and reference it from elsewhere in the same document.
My audit says my Organization markup is incomplete but it looks fine. Why?
Probably because the blocks it flagged are @id references to a definition elsewhere in the graph. A reference carries no properties by design, and a tool reading it as its own entity will call it incomplete.
Can an @id point at a definition on another page?
No, not usefully. Structured data is read one page at a time, so a reference to a node defined on a different page resolves to nothing on the page that carries the reference.
Why does no validator catch a dangling @id?
Because it is valid JSON-LD. Validators check syntax; this is a failure of resolution. A rich-results test reports that nothing was found, which reads like missing markup rather than a pointer to nowhere.
Should I add the missing properties to each reference block?
No. That duplicates a definition rather than fixing one. Either define the entity on each page that references it, or remove the stub — as it stands it produces neither a rich result nor an error.