Structured Data Became Invalid After a Template Change

A template refactor or framework upgrade broke JSON-LD blocks site-wide. How to detect and fix.

You refactored your article layout, upgraded Astro / Next.js / Hugo, or renamed a frontmatter field. A week later Search Console emails you: “Structured data issues detected — N URLs now invalid.” Enhancements → Articles / FAQPage / BreadcrumbList shows a spike of red. Rich Results Test on a sample URL fails. This pattern has a small number of recurring causes — a renamed template variable that the JSON-LD still references by old name, a serializer change in the framework that altered date format, a new layout wrapper that swallowed the <script type="application/ld+json"> block, or a conditional render path that excludes some pages. None of them require rewriting the schema from scratch. Find the one broken field and fix it.

Identify which case you are in (15 seconds)

Open the failing URL in Rich Results Test. Read the exact error message, not your interpretation of it. The error wording maps to specific causes:

Rich Results Test errorMost likely cause
Missing field "datePublished" / "author" / "image"Renamed frontmatter field; JSON-LD still references the old name and gets undefined
Invalid object type for field "X"Framework upgrade changed how a value serializes (Date → string, array → object)
Parsing error: ... or “No structured data detected”The JSON-LD block is no longer in the rendered HTML — wrapper / hydration / conditional dropped it
Either "image" or "thumbnailUrl" should be specifiedImage helper now returns relative URL or null
BreadcrumbList: itemListElement must contain at least 2 itemsBreadcrumb generator now returns 0 or 1 items for some routes
FAQPage: At least one mainEntity is requiredFAQ generator runs on pages with no Q/A sections; emits empty schema

Common causes, ranked by hit rate

1. Renamed a frontmatter field — JSON-LD still references the old name

You renamed pubDate to publishedAt in the content collection schema. The JSON-LD template still reads frontmatter.pubDate, which is now undefined. The output looks like:

{
  "@context": "https://schema.org",
  "@type": "Article",
  "datePublished": null
}

Google rejects null / missing required fields.

How to spot it: view-source the page, find the <script type="application/ld+json"> block, look for null, missing keys, or fields that should be populated but are empty strings.

Fix: grep the codebase for every field name your JSON-LD generator references and verify each one against the current frontmatter schema. A simple guard:

const datePublished = frontmatter.publishedAt ?? frontmatter.pubDate;
if (!datePublished) throw new Error(`Missing publishedAt for ${slug}`);

Fail the build on missing required fields — quieter than catching it in Search Console two weeks later.

2. Framework upgrade changed serialization

A common gotcha after Astro / Next.js minor upgrades: Date objects used to serialize to ISO strings via JSON.stringify; now they serialize to {} or to a localized string. The same with arrays of objects being flattened.

How to spot it: diff view-source between the last working commit and current. Look for fields that used to be "2026-05-19T00:00:00.000Z" and are now "5/19/2026" or {}.

Fix: always coerce dates to ISO 8601 explicitly:

const datePublished = new Date(frontmatter.publishedAt).toISOString();

And serialize arrays explicitly rather than relying on JSON.stringify defaults.

3. A new layout wrapper swallowed the JSON-LD block

You added a <MarketingShell> or <ArticleFrame> component around the article body. If that component renders its own <head> slot or strips children, your <script type="application/ld+json"> may no longer reach the document head.

How to spot it: Rich Results Test says “No structured data detected.” view-source the page: the JSON-LD <script> block is missing entirely. It was emitted in the template source but didn’t survive rendering.

Fix: in Astro, use <Fragment slot="head"> or render the script directly inside the layout’s <head>. In Next.js, use the <Head> component or App Router’s generateMetadata / Script with strategy="beforeInteractive". In Hugo, ensure your partial is included in head.html.

4. Conditional render path drops schema for a subset of pages

Your template has {frontmatter.draft ? null : <JsonLd />} or {frontmatter.type === 'guide' && <JsonLd />}. After a refactor, the condition now excludes more pages than intended — e.g., legacy articles where type is undefined.

How to spot it: Search Console Enhancements shows an exact count of “valid items” that dropped. Filter URLs and notice they all share a frontmatter trait (legacy date, missing field, specific category).

Fix: make the JSON-LD generator unconditional. Emit null only when truly inapplicable (e.g., FAQPage when no Q/A exists). For Article / BreadcrumbList / WebSite, always emit.

5. BreadcrumbList itemListElement count mismatch

After a route refactor, the breadcrumb generator returns 1 item for some routes (Home) or returns the same item twice (Home > Home > Article). Google requires at least 2 items and items must be unique positions.

{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://yourdomain.com/" },
    { "@type": "ListItem", "position": 2, "name": "Troubleshooting", "item": "https://yourdomain.com/troubleshooting/" },
    { "@type": "ListItem", "position": 3, "name": "Article title" }
  ]
}

Note: the last item must NOT have an item URL — it represents the current page.

A copy-ready Article + Breadcrumb template

{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "Article title under 110 characters",
  "description": "One-sentence summary",
  "image": "https://yourdomain.com/og/article.png",
  "datePublished": "2026-05-19T00:00:00.000Z",
  "dateModified": "2026-05-22T00:00:00.000Z",
  "author": {
    "@type": "Person",
    "name": "Author Name",
    "url": "https://yourdomain.com/about/"
  },
  "publisher": {
    "@type": "Organization",
    "name": "Site name",
    "logo": {
      "@type": "ImageObject",
      "url": "https://yourdomain.com/logo.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://yourdomain.com/articles/article-slug/"
  }
}

Shortest fix path

In hit-rate order:

  1. Read the exact Rich Results Test error verbatim: it tells you the broken field
  2. View-source the page and inspect the JSON-LD block: find null, missing key, or stale field name
  3. Diff the template against the last working commit: most issues regress from one specific change
  4. Add a build-time JSON-LD validator that fails on missing required fields — prevents the next regression
  5. Re-request indexing in Search Console URL Inspection on a sample page; Enhancements report clears in 1-3 weeks

Prevention

  • Snapshot Rich Results Test output for one URL per template in CI. Fail the build if the snapshot diff shows new errors.
  • Validate JSON-LD against the Schema.org JSON Schema on every build (use structured-data-testing-tool or run schema-dts type-checking).
  • Never reference frontmatter fields directly in JSON-LD templates — go through a typed helper that throws on missing required fields.
  • After any framework upgrade, manually run Rich Results Test on one URL per content type before merging.
  • Keep a “schema canary” route — a fixture page with every supported schema type — and check it in CI.

FAQ

Q: Will broken JSON-LD hurt my ranking? A: It hurts rich result eligibility, not the underlying ranking. Your blue-link result stays put; you just lose the star ratings, FAQ accordion, breadcrumb display, video thumbnail, etc. For commerce / recipes / events, the rich result loss is significant.

Q: Should I remove the JSON-LD entirely if I cannot fix it quickly? A: Yes. Shipping invalid schema is worse than shipping no schema — Google logs the failures and may downweight your domain’s rich result eligibility over time. Remove first, fix, reinstate.

Q: Enhancements report still shows “Invalid” after I fixed it. How long until it clears? A: Search Console Enhancements re-validates as Google re-crawls. Expect 1-3 weeks for the count to drop. Verify the fix immediately via Rich Results Test on a sample URL — that is ground truth.

Q: Rich Results Test says “Valid” but Google does not show the rich result. A: Validation is necessary but not sufficient. Google also weighs content quality, freshness, and user signals. Some schema types (FAQPage, HowTo) have been deprecated or restricted to specific verticals as of 2026 — check current eligibility for your type.

Q: I have multiple JSON-LD blocks on one page. Is that OK? A: Yes. One Article + one BreadcrumbList + one WebSite is standard. Just do not duplicate the same @type with different values — Google may pick either one or ignore both.

Tags: #SEO #Troubleshooting #Debug #Structured data #JSON-LD