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

  1. Move the {{ inner }} call into the decorator partial's template file itself, not the with block body at the call site.
  2. Restructure so the content that should be wrapped is the with block body, and the partial template uses inner to emit it.
  3. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/7a75125cfed54f15.json. Report an issue: GitHub ↗.