gohugoio/hugo · error

resources.PostProcess cannot be used in a deferred template

Error message

resources.PostProcess cannot be used in a deferred template

What it means

Thrown during template AST transformation when a deferred template (a `with`/partial marked with `defer`) contains a reference to resources.PostProcess (tpl/tplimpl/templatetransform.go:451-453). Hugo forbids PostProcess inside deferred execution because the deferred pass runs after the resources pipeline is already finalized, so deferred PostProcess could never take effect.

Solutions

  1. Move the resources.PostProcess call out of the deferred template into a non-deferred partial or the base template.
  2. Remove the `defer` argument from the partial/with that wraps the PostProcess call.
  3. If you need late CSS injection, use a non-deferred resource with appropriate fingerprinting instead of PostProcess.

Example fix

// before (inside deferred partial)
{{ partial "head.html" (dict "defer" true ...) }}
  {{ resources.Get "app.css" | resources.PostProcess }}
// after (PostProcess moved to non-deferred template)
{{ partial "head.html" ... }}
{{ resources.Get "app.css" | resources.PostProcess }}
Defensive patterns

Strategy: validation

Validate before calling

{{/* Move resources.PostProcess out of any partial invoked with defer=true */}}

Prevention

When it happens

Trigger: Placing {{ (resources.Get "x.css" | resources.PostProcess) }} inside a template invoked via a `defer` argument (e.g. a deferred partial or a with/defer block).

Common situations: Refactoring a CSS/JS pipeline into a deferred partial for performance; using PostProcess in a header partial that is itself deferred; theme updates that introduced defer on partials that contain PostProcess.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/0213c2e43ce1b9b3. Report an issue: GitHub.

Appendix: source

Thrown at tpl/tplimpl/templatetransform.go:453

		return
	}

	idArg = cmd.Args[0]

	if !c.isWithDefer(idArg) {
		return
	}

	deferArg := cmd.Args[1]
	cmd.Args = []parse.Node{idArg}

	l := doDefer.CopyList()
	n := l.Nodes[0].(*parse.ActionNode)

	inner := withNode.List.CopyList()
	s := inner.String()
	if strings.Contains(s, "resources.PostProcess") {
		c.err = errors.New("resources.PostProcess cannot be used in a deferred template")
		return
	}
	innerHash := hashing.XxHashFromStringHexEncoded(s)
	deferredID := tpl.HugoDeferredTemplatePrefix + innerHash

	c.deferNodes[deferredID] = inner
	withNode.List = l

	n.Pipe.Cmds[0].Args[1].(*parse.PipeNode).Cmds[0].Args[0].(*parse.StringNode).Text = deferredID
	n.Pipe.Cmds[0].Args[2] = deferArg
}

func (c *templateTransformContext) applyTransformationsToNodes(nodes ...parse.Node) {
	for _, node := range nodes {
		c.applyTransformations(node)
	}
}

View on GitHub (pinned to 52c9bd7908)