Google Search Console flagged a real estate site I work on yesterday with this error on the /about page:
Invalid object type for field 'mainEntity'
The page validated clean on schema.org's validator. It validated clean on Google's Rich Results Test. The JSON-LD parsed without complaint in every browser console. Search Console flagged it anyway, and the rich-result on the page got marked ineligible.
The pattern is common. If you put your Person or Organization entity on the homepage and reference it from a separate /about page, you probably have this bug, and Search Console will tell you about it eventually.
What the bug looks like
The homepage carries the canonical Person definition:
{
"@context": "https://schema.org",
"@type": "Person",
"@id": "https://example.com/#seth-watte",
"name": "Seth Watte",
"url": "https://example.com/",
"jobTitle": "Real Estate Agent",
"worksFor": {"@id": "https://example.com/#organization"}
}
The /about page has the ProfilePage rich-result wrapper, which references that Person by @id:
{
"@context": "https://schema.org",
"@type": "ProfilePage",
"@id": "https://example.com/about/#profilepage",
"mainEntity": {"@id": "https://example.com/#seth-watte"},
"dateCreated": "2026-04-01",
"dateModified": "2026-05-13"
}
That reads correctly to a JSON-LD parser. The Person at https://example.com/#seth-watte is defined on the homepage. The /about page's ProfilePage points back at it. Schema.org's data model explicitly allows cross-document @id references.
Search Console disagrees. The validator emits "Invalid object type for field 'mainEntity'" because, on the /about page in isolation, the reference is just {"@id": "https://example.com/#seth-watte"}. There is no @type hint on the reference itself. There is no inline definition of the Person on this page. Search Console's strict validator cannot determine what mainEntity is supposed to be, so it flags the field as having an invalid object type.
Why the validators give different answers
Schema.org's validator answers the question "is the JSON-LD structurally valid and do the field types match the spec?" It walks the document and the answer is yes. A Person is allowed as mainEntity on a ProfilePage. The reference is structurally a valid @id pointer.
Google's Rich Results Test answers a similar question, scoped to whether the JSON-LD is eligible to produce a rich result. It runs more checks than schema.org but it still does not fail this pattern.
Google Search Console's rich-result report uses a stricter validator. It is the same validator that decides whether your ProfilePage actually appears in search results. It treats every page as a self-contained document for validation purposes. If the type of mainEntity cannot be established from this document alone, it flags the field.
The contradiction is real. Schema.org says cross-document @id references are valid. Search Console's rich-result validator wants the type either inline on the reference or defined inline on the same page. You have to satisfy both.
Fix A: type the reference inline
The cheapest fix is to add the @type alongside the @id on the reference itself:
{
"@type": "ProfilePage",
"@id": "https://example.com/about/#profilepage",
"mainEntity": {
"@id": "https://example.com/#seth-watte",
"@type": "Person"
},
"dateCreated": "2026-04-01T00:00:00-06:00",
"dateModified": "2026-05-13T00:00:00-06:00"
}
The reference now carries enough information for Search Console to resolve the type without fetching the homepage. The @id still points at the canonical Person on the homepage, so the Knowledge Graph treats it as one entity. Both validators are satisfied.
Note that I also fixed the date-only issue at the same time. Search Console flags "dateModified": "2026-05-13" with "Invalid datetime value for dateModified" for the same class of strict-validator reason. See the companion post on ISO 8601 datetime fields for the timezone-offset rules.
Fix B: define the entity inline on the same page
The stronger pattern is to define the Person inline on the /about page directly, while keeping the same @id so it stays one entity for the Knowledge Graph:
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Person",
"@id": "https://example.com/#seth-watte",
"name": "Seth Watte",
"url": "https://example.com/",
"jobTitle": "Real Estate Agent",
"worksFor": {"@id": "https://example.com/#organization"}
},
{
"@type": "ProfilePage",
"@id": "https://example.com/about/#profilepage",
"mainEntity": {"@id": "https://example.com/#seth-watte"},
"dateCreated": "2026-04-01T00:00:00-06:00",
"dateModified": "2026-05-13T00:00:00-06:00"
}
]
}
JSON-LD merges nodes by @id. The Person defined on the homepage and the Person defined inline on the /about page collapse into one entity in the Knowledge Graph because they share the same @id. Search Console gets a typed Person inline on the document, so the strict validator passes. AI Mode gets a Person inline on the page that the ProfilePage describes, which is the binding direction it actually prefers when it picks a canonical bio page for a name query.
Fix B is more lines of HTML and more bytes per page, but it is the pattern I recommend when the page IS the bio page for the entity. ProfilePage exists specifically to flag a page as the canonical home of a person or organization. Defining that entity inline on its own canonical page is more consistent with how AI Mode walks the graph than relying on a cross-document reference.
Cases where Fix A is right and Fix B is wrong
The author bio page is one case where Fix B fits. Other cases need Fix A.
If a blog post emits an Article with author: {"@id": "https://example.com/#seth-watte"} and the page is not the author's bio page, do not inline the full Person definition on the Article page. Inlining the Person on every Article page means the canonical Person definition exists in fifty different places, with potential drift in alternateName, sameAs, and other fields. Use Fix A on Article pages. Reference the Person by @id with an inline @type: Person hint, and let the canonical definition live on the bio page only.
The shape of the rule. Inline-define an entity on exactly one page (the page that IS the entity's canonical home). Reference it with @id plus inline @type hint everywhere else. Search Console is happy. The Knowledge Graph treats it as one entity. AI Mode follows the canonical-bio binding when name-only queries fire.
How to find every occurrence
The mega analyzer detector for this bug walks every JSON-LD block on the page, collects the set of @id values that are inline-defined with a @type, then walks ProfilePage / AboutPage / WebPage / CollectionPage / Article / BlogPosting / NewsArticle nodes and checks every mainEntity / about / author / publisher field. If the field value is {"@id": "..."} with no @type and the referenced @id is not in the inline-defined set, it surfaces the field as a Search Console risk.
You can run the same check by hand in DevTools:
const blocks = [...document.querySelectorAll('script[type="application/ld+json"]')];
const definedIds = new Set();
const checkRefs = [];
const BIND_FIELDS = ['mainEntity', 'about', 'author', 'publisher'];
const PAGE_TYPES = /^(ProfilePage|AboutPage|WebPage|CollectionPage|Article|BlogPosting|NewsArticle|ItemPage)$/;
function walk(n, fn) {
if (!n || typeof n !== 'object') return;
if (Array.isArray(n)) return n.forEach(x => walk(x, fn));
fn(n);
for (const k of Object.keys(n)) if (n[k] && typeof n[k] === 'object' && k !== '@type') walk(n[k], fn);
}
blocks.forEach(b => {
try {
const data = JSON.parse(b.textContent);
walk(data, n => {
const tt = Array.isArray(n['@type']) ? n['@type'] : [n['@type']].filter(Boolean);
if (n['@id'] && tt.length > 0) definedIds.add(n['@id']);
});
walk(data, n => {
const tt = Array.isArray(n['@type']) ? n['@type'] : [n['@type']].filter(Boolean);
if (tt.some(t => PAGE_TYPES.test(t))) {
BIND_FIELDS.forEach(f => {
const v = n[f];
const check = vv => {
if (vv && typeof vv === 'object' && !Array.isArray(vv) && vv['@id'] && !vv['@type']) {
checkRefs.push({parent: tt[0], field: f, ref: vv['@id'], inline: definedIds.has(vv['@id'])});
}
};
if (Array.isArray(v)) v.forEach(check); else check(v);
});
}
});
} catch (e) {}
});
const unresolved = checkRefs.filter(r => !r.inline);
console.log({total: checkRefs.length, unresolved});
Anything in the unresolved array is what Search Console flags.
Why this matters for AI search
Schema validators are answering one question. Search Console is answering a stricter version of that same question. AI search retrievers (Google AI Mode, Gemini, Perplexity) are answering a different question entirely.
When AI Mode resolves a name-only query to one URL, it follows a chain of bindings. Person at homepage @id. Person.mainEntityOfPage object pointing at the /about page's ProfilePage @id. ProfilePage.mainEntity pointing back at the Person @id. The bidirectional loop tells AI Mode that the /about page is the canonical bio for this Person.
The bug under discussion breaks the loop one way. ProfilePage cannot establish that mainEntity is a Person without fetching the homepage. Search Console flags it as a rich-result error. AI Mode's confidence drops because the binding is one-sided. Either fix restores the loop. Fix A by inline-typing the reference. Fix B by inline-defining the entity.
If you operate a site where the same Person or Organization is referenced from multiple URLs, the audit habit to build is grep every <script type="application/ld+json"> block for bare {"@id": "..."} references on mainEntity / about / author / publisher fields, then check whether the referenced @id is defined as a typed node on the same page. If not, fix it before Search Console finds it.
When the bug shipped on this site
This bug shipped on the yoseth.com /about page on 2026-05-13 as part of a ProfilePage migration that consolidated the bio pattern across sites. The migration moved Person definitions to the homepage to avoid duplication, then referenced them from /about with bare @id pointers. The validators all passed. Search Console reported the error three days later when the next crawl finished. The detector in the mega analyzer was added the same day Search Console flagged it, so other sites that copied the same pattern will surface this bug before deploy now.
Related reading
- The companion ISO 8601 datetime post — the other Search Console strict-validator error that ships in the same regression
- Nine AI Mode entity-binding bugs that pass every schema validator — the predecessor post; this is bug ten
- Your schema validates. Google AI Mode still cannot find you. — broader entity-anchor pattern
- Schema validator vs Rich Results vs Search Console — three validators, three different verdicts — why the three validators diverge
- The Mega Analyzer — where this detector lives in the audit chain
Fact-check notes and sources
- Schema.org Person and ProfilePage types: schema.org/Person, schema.org/ProfilePage
- JSON-LD 1.1
@idcross-document reference spec: www.w3.org/TR/json-ld11/#node-identifiers - Google ProfilePage rich-result guidance: developers.google.com/search/docs/appearance/structured-data/profile-page
- Search Console rich-result error reference: support.google.com/webmasters/answer/7552505
This post is informational, not legal or SEO-consulting advice. Examples reference my own sites and sites I work on, with no third party named as a negative case study.