gohugoio/hugo · error
inner cannot be used inside a with block that wraps a partia
Error message
inner cannot be used inside a with block that wraps a partial decorator
What it means
Hugo's partial decorator feature lets a {{ with (partial ...) }} block wrap content, with {{ inner }} (matched by templatesInnerRe) providing the wrapped content. Hugo hoists the with-block body into an internal generated partial, and calling inner inside that body would recurse into the decorator machinery itself, so the transformer rejects it at build time.
Source
Thrown at tpl/tplimpl/templatetransform.go:327
case *parse.WithNode:
if c.hasBreakOrContinueOutsideRange(x.List) {
return true
}
if c.hasBreakOrContinueOutsideRange(x.ElseList) {
return true
}
case *parse.BreakNode, *parse.ContinueNode:
return true
}
}
return false
}
func (c *templateTransformContext) handleWithPartial(withNode *parse.WithNode) {
withNodeInnerString := withNode.List.String()
if templatesInnerRe.MatchString(withNodeInnerString) {
c.err = fmt.Errorf("inner cannot be used inside a with block that wraps a partial decorator")
return
}
// See #14333. That is a very odd construct, but we need to guard against it.
if c.hasBreakOrContinueOutsideRange(withNode.List) {
return
}
innerHash := hashing.XxHashFromStringHexEncoded(c.t.Name() + withNodeInnerString)
internalPartialName := fmt.Sprintf("_partials/%s%s", PartialDecoratorPrefix, innerHash)
if c.lookupFn(internalPartialName, c.t) == nil {
innerCopy := withNode.List.CopyList()
ti, err := c.store.addTransformedTemplateInsert(internalPartialName, SubCategoryInline)
if err != nil {
c.err = fmt.Errorf("failed to create internal partial decorator template %q: %w", internalPartialName, err)
return
}
if ti == nil {View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Move the {{ inner }} call into the decorator partial's template file itself, not the with block body at the call site.
- Restructure so the content that should be wrapped is the with block body, and the partial template uses inner to emit it.
- If you need nested wrapping, nest two decorator calls rather than putting inner in the outer with body.
Example fix
<!-- before: layouts/page.html -->
{{ with partial "card.html" . }}
{{ inner }}
{{ end }}
<!-- after: layouts/page.html -->
{{ with partial "card.html" . }}
<p>Wrapped content</p>
{{ end }}
<!-- layouts/_partials/card.html -->
<div class="card">{{ inner }}</div> Defensive patterns
Strategy: validation
Validate before calling
{{/* Don't do this: */}}
{{/* {{ with .Foo }}{{ partial "p" . }}{{ .Inner }}{{ end }} */}}
{{/* Instead resolve the value first, keep inner outside with */}}
{{ $v := .Foo }}
{{ partial "p" (dict "ctx" . "v" $v) }} Prevention
- Never place `.Inner` of a partial decorator inside a `with` block wrapping that partial
- Hoist values into variables with `$x := ...` instead of wrapping decorator calls in with
- Keep partial-decorator call sites structurally flat
When it happens
Trigger: handleWithPartial finds a match for the inner keyword inside the body (List) of a with node that wraps a partial decorator call — i.e. {{ with partial "x" . }}...{{ inner }}...{{ end }} where the with block itself is the decorator wrapper.
Common situations: Authors writing shortcode-like wrapper partials confuse the decorator pattern: inner belongs inside the decorator partial's own template, not inside the with block at the call site. Often hit when refactoring nested wrapper components or copying examples incorrectly.
Related errors
- partial %q not found
- circular call stack detected in partial %q
- maximum template call stack size exceeded in %q
- 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/7a75125cfed54f15.json.
Report an issue: GitHub ↗.