Hugo 0.165.0-0.166.0 upgrade guide

Hugo 0.166.0’s security hardening, and a few smaller changes, can break a Docsy site’s build or silently change its output. Find the ones that apply to your site, each with its fix.

This post is a companion to the Docsy 0.18.0 release post, which names the Hugo version that 0.18.0 supports.

Upgrade summary

Security hardening (0.166.0)

Hugo 0.166.0 is mostly a hardening release: it drops symlinked mounts, confines Node tools to allowed roots, checks the addresses that remote fetches resolve to, and denies Org mode content by default. Each item can stop a site’s build or silently drop its files. For the details, see Hugo’s 0.166.0 release notes.

Actions

Applies if your project has a symlink that resolves outside it, under node_modules for example. Hugo 0.166.0 fails PostCSS and other Node tools before running them when a symlink escapes the allowed roots.

  • Set security.node.permissions.allowRead to the whole list with the link’s target added, ['.', 'TARGET'], where TARGET is the path the link resolves to.

Applies if a symlink sits on a mount’s path, wherever it points: a mount root such as assets/ or a module mount’s source (dropped since 0.166.0), a directory inside one such as assets/vendor/x (dropped since 0.165.0), or a relative source that passes through a link. A symlinked theme directory (themes/docsy -> ../docsy) still mounts, but counts as a symlink that resolves outside the project for the Node gate above when PostCSS runs (Docsy runs it in production with a postcss.config.*, and for RTL languages). Docsy’s own mounts read two node_modules packages through three mounts, which pnpm and npm link install as symlinks: the Bootstrap and Font Awesome Sass imports then fail with no pointer to the cause, and the Font Awesome webfonts vanish from an otherwise green build.

  • Replace the link with the real directory (pnpm: node-linker=hoisted), or mount the link’s target by an absolute source, for every mount the link affects, and re-declare your project’s own assets and static mounts: a project mount for a component replaces Hugo’s default mount for it, silently.

Applies if your build runs behind an HTTP_PROXY or HTTPS_PROXY. Docsy itself fetches Mermaid, MarkMap, and KaTeX assets at build time, so a proxied build is affected even if your templates fetch nothing: Hugo 0.166.0 ignores the proxy variables unless told to honor them.

  • Set security.http.proxyFromEnvironment to true.

Applies if your build fetches resources from a private or internal host. Hugo 0.166.0 rejects loopback, private, link-local, and CGNAT addresses under the default security.http.urls allowlist.

  • Set security.http.urls to a list naming your hosts and the CDNs Docsy fetches from (cdn.jsdelivr.net, unpkg.com): the address check stands down for a customized list.

Applies if your content includes Org mode files (.org). Hugo 0.166.0 denies text/org by default, as it passes raw HTML through.

  • Opt back in by setting security.allowContent to the whole list without the text/org denial: ['! ^text/html$'].

Glob patterns rewritten (0.166.0)

Hugo 0.166.0 replaced its glob-matching engine. Patterns that relied on the old engine’s bugs match differently; literal paths are unaffected.

  • **/ matches one or more directories; the old engine also let it match none:
    • **/x no longer matches a top-level x. Add x as a second pattern; the {**/,}x alternation matches nothing before 0.166.0.
    • a/**/b no longer matches a/b.
  • \ is an escape character.
  • Malformed patterns fail the build.

Actions

Applies if your site uses glob patterns:

  • In config: module mounts’ includeFiles, excludeFiles, and files; cascade targets; segments; deployment targets’ include and exclude; noVendor.
  • In templates: .Resources.Match, resources.Match, and kin.

Then:

  • Re-test each pattern against the files it should select.
  • For a ! exclusion, also check the built output for files that should be absent: a pattern that stops matching publishes them with no warning.

KaTeX stylesheet floor (0.166.0)

Hugo 0.166.0’s bundled KaTeX, the one behind transform.ToMath and Docsy’s math fences, emits markup that needs a KaTeX 0.18.4 or later stylesheet; an older one misrenders some expressions. Docsy 0.18.0’s pin, KaTeX 0.18.9, satisfies it (dependency versions).

Actions

Applies if your site renders math and serves a KaTeX stylesheet below 0.18.4, through params.katex.version or an overridden scripts/katex.html.

  • Remove your pin to take Docsy’s default, KaTeX 0.18.9, or update an overridden partial’s stylesheet to it; for a custom pin, see KaTeX version.

Imaging config deprecations now warn (0.166.0)

Hugo 0.163.0 deprecated the global imaging.quality and imaging.compression keys for per-format ones (Hugo 0.158+ guide); 0.166.0 raises the notice to a build WARN, which fails the update guide’s no-warnings check.

Actions

Applies if your site config still sets imaging.quality or imaging.compression.

URL and template changes (0.166.0)

Two smaller 0.166.0 changes can move a page or truncate one: a title’s / no longer splits a title-derived URL into two segments, and a bare return now works in every template, where it used to be ignored outside partials.

Actions

Applies if your permalinks use :title, or :slug on pages that set no slug, and a title contains a /. Hugo 0.166.0 derives one URL segment from the title (watch-listen-to-this) where it used to nest two (watch/listen-to-this), so the page’s URL moves without a redirect; filename-based URLs, taxonomy pages, and term pages are unaffected.

  • Add an aliases entry for the old URL. Under :slug, an explicit slug keeps it; under :title, it doesn’t.

Applies if your own templates use return outside a partial. Hugo 0.166.0 honors it there: a bare {{ return }}, ignored before, now ends the template’s output; return with a value fails the build, as it did before.

  • Remove it, or move the logic into a partial.

Tailwind allow-list (0.165.0)

Hugo 0.165.0 is a feature release (notes); besides the symlink rule above, its change for Docsy sites is that tailwindcss left the default security.exec.allow list.

Actions

Applies if your site runs Tailwind through css.TailwindCSS.

  • Set the list with tailwindcss added back:

    security:
      exec:
        allow:
          [
            '^(dart-)?sass$',
            '^go$',
            '^git$',
            '^node$',
            '^postcss$',
            '^tailwindcss$',
          ]
    

Upgrade to Hugo 0.166.0

After addressing the actions that apply to your site, upgrade to Hugo 0.166.0 (Update Hugo).

Sanity checks

Confirm that you’ve addressed every action that applies to your site. Then: