gohugoio/hugo · error
templates.Defer cannot be used inside a partialCached…
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
Thrown by templates.Defer when tpl.Context.IsInPartialCached is set on the context, i.e. the Defer block lives inside a partialCached body. The cached output retains the deferred placeholder across rebuilds while the executions map resets, which previously caused a panic in executeDeferredTemplates (issue #13492).
Solutions
- Switch the calling partial from partialCached to plain partial.
- Move the templates.Defer block up to the page/layout template that calls the partial.
- Split the partial so the deferred portion lives outside the cached boundary.
- Re-evaluate whether caching is needed if the content depends on deferred data.
Example fix
// before (Defer inside partialCached body):
{{ partialCached "widget.html" . }} // widget.html contains templates.Defer
// after (call without caching):
{{ partial "widget.html" . }} Defensive patterns
Strategy: validation
Validate before calling
{{ if not $.InPartialCached }}{{ templates.Defer }}…{{ end }} Prevention
- Never place templates.Defer inside a partialCached body.
- Use plain partial for any partial containing a Defer block.
- Move deferred blocks to the calling layout/page template.
When it happens
Trigger: Using {{ templates.Defer (…) }} …{{ end }} inside a partial that is invoked via partialCached. The guard fires at the start of Defer regardless of arguments.
Common situations: Migrating from resources.PostProcess to templates.Defer inside a cached partial, or wrapping a deferred heavy block in partialCached for performance. The fix is structural: the deferred block must not be cached.
Related errors
- Defer does not take any arguments
- alignx must be one of left, center, right
- can't apply the operator to the values
- circular call stack detected in partial
- error building site
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/e5aaf6d571188963.
Report an issue: GitHub.
Appendix: 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 52c9bd7908)