gohugoio/hugo · error
templates.Defer cannot be used inside a partialCached partia
Error message
templates.Defer cannot be used inside a partialCached partial; use partial instead, or move templates.Defer to the calling template
What it means
`templates.Defer` postpones rendering of a block until after the site build (used e.g. for TailwindCSS class collection). Its output placeholder is incompatible with `partialCached`: the cached partial output would retain the deferred placeholder across rebuilds while the deferred-executions map is reset, which previously caused a panic in executeDeferredTemplates (see issue #13492). Hugo now detects the combination via the `IsInPartialCached` context flag and fails with this explicit error (tpl/templates/templates.go:64-66).
Source
Thrown at tpl/templates/templates.go:65
// Exists returns whether the template with the given name exists.
// Note that this is the Unix-styled relative path including filename suffix,
// e.g. partials/header.html
func (ns *Namespace) Exists(name string) bool {
return ns.deps.GetTemplateStore().HasTemplate(name)
}
// Defer defers the execution of a template block.
func (ns *Namespace) Defer(ctx context.Context, args ...any) (bool, error) {
// Prevent defer from being used in content adapters,
// that just doesn't work.
ns.deps.Site.CheckReady()
// Reject use inside a partialCached body: the cached output retains the
// deferred placeholder across rebuilds while the executions map is reset,
// which used to cause a panic in executeDeferredTemplates. See issue #13492.
if tpl.Context.IsInPartialCached.Get(ctx) {
return false, fmt.Errorf("templates.Defer cannot be used inside a partialCached partial; use partial instead, or move templates.Defer to the calling template")
}
if len(args) != 0 {
return false, fmt.Errorf("Defer does not take any arguments")
}
return true, nil
}
var defferedIDCounter atomic.Uint64
type DeferOpts struct {
// Optional cache key. If set, the deferred block will be executed
// once per unique key.
Key string
// Optional data context to use when executing the deferred block.
Data any
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Change the `partialCached` call that includes the deferred block to a plain `partial` call.
- Alternatively, move the `templates.Defer` block out of the cached partial and into the calling template (e.g. baseof.html), keeping the rest of the partial cached.
- If the deferred work itself is expensive, use `templates.Defer (dict "key" ...)` — Defer has its own per-key caching, so partialCached is unnecessary around it.
Example fix
<!-- before: layouts/baseof.html -->
{{ partialCached "css.html" . }}
<!-- partials/css.html contains {{ with (templates.Defer (dict "key" "css")) }}...{{ end }} -->
<!-- after -->
{{ partial "css.html" . }}
<!-- or move the templates.Defer block directly into baseof.html --> Defensive patterns
Strategy: validation
Validate before calling
{{/* structural rule, checked at authoring time: */}}
{{/* BAD: {{ partialCached "head.html" . }} where head.html uses templates.Defer */}}
{{/* GOOD: use {{ partial "head.html" . }} or hoist templates.Defer to the caller */}} Prevention
- Never place templates.Defer inside a partial invoked via partialCached — the deferred block would be cached and skipped
- Switch that call site to plain partial, or move the templates.Defer block up into the calling template
- Grep your theme for `templates.Defer` when adding partialCached wrappers
When it happens
Trigger: A template calls `{{ partialCached "foo.html" . }}` and inside foo.html (or any partial it includes) there is a `{{ with (templates.Defer ...) }}` block. Triggers on server rebuilds and regular builds alike once the guard runs.
Common situations: Wrapping a site head/footer partial that contains the TailwindCSS `templates.Defer` snippet in partialCached for performance; themes updated to use templates.Defer while the site wraps theme partials in partialCached; upgrading Hugo past the version that added this guard turns a previously panicking or silently broken setup into this error.
Related errors
- Defer does not take any arguments
- circular call stack detected in partial %q
- resources.PostProcess cannot be used in a deferred template
- error building site: %w
- failed to detect format from content
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/e5aaf6d571188963.json.
Report an issue: GitHub ↗.