Skip to content

docs: add canonical pattern for JSON-LD in <script> tags (jsonify + safeHTML produces double-encoded JSON) #3409

@luismattos

Description

@luismattos

Description

When using {{ dict ... | jsonify | safeHTML }} inside <script type="application/ld+json">, the output is double-encoded JSON — a JSON string literal wrapped in quotes instead of a JSON object:

// Actual output (broken):
"{"@context":"https://schema.org","@type":"WebSite"}"

// Expected output:
{"@context":"https://schema.org","@type":"WebSite"}

Root cause

Go's html/template is context-aware. Inside <script> tags, it applies JS-context escaping regardless of the type attribute. safeHTML returns template.HTML which bypasses HTML escaping, but does NOT bypass JS-context escaping. The template engine treats the content as a JS value and wraps it in quotes with escaped inner quotes.

This is not a Hugo bug — it's standard html/template behavior. But it's a documentation gap that affects every Hugo theme using JSON-LD structured data.

Correct pattern

{{/* Build the entire <script> tag as a string, bypassing JS-context */}}
{{ $data := dict "@context" "https://schema.org" "@type" "WebSite" "name" .Title }}
{{ printf `<script type="application/ld+json">%s</script>` ($data | jsonify) | safeHTML }}

Incorrect patterns (commonly used)

{{/* BROKEN: safeHTML does not bypass JS-context escaping inside <script> */}}
<script type="application/ld+json">
{{ dict "@context" "https://schema.org" "@type" "WebSite" | jsonify | safeHTML }}
</script>

{{/* ALSO PROBLEMATIC: safeJS has known issues with partials (#8001) */}}
<script type="application/ld+json">
{{ dict "@context" "https://schema.org" "@type" "WebSite" | jsonify | safeJS }}
</script>

Impact

This silently breaks ALL structured data (JSON-LD) on affected sites. Google Search Console shows 0 rich results, and site owners assume it's a configuration issue. The broken JSON is syntactically valid (it's a JSON string), so it doesn't cause build errors.

Related issues

None of these document the double-encoding mechanism or provide the correct pattern.

Request

Add a canonical JSON-LD example to the encoding.Jsonify documentation page showing the printf + safeHTML pattern. This would prevent the most common structured data bug in Hugo themes.

Environment

  • Hugo v0.156.0
  • macOS, hugo --minify
  • Reproducible on all versions using html/template

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions