gohugoio/hugo · error

failed to transform internal partial decorator template

Error message

failed to transform internal partial decorator template %q: %w

What it means

Once the internal partial decorator template is created and its tree set, Hugo recursively runs the AST transformer on it (cc.applyTransformationsAndSetReturnWrapper, templatetransform.go:358-360). If that recursive transform fails, the error is wrapped with the decorator name. This catches nested transform errors in the synthesized template.

Solutions

  1. Read the wrapped error from the recursive applyTransformationsAndSetReturnWrapper.
  2. Simplify the body of the with-partial block to find the offending nested construct.
  3. Update Hugo to the latest release.
  4. Report with a minimal reproducer if it reproduces on stock Hugo.
Defensive patterns

Strategy: try-catch

Try / catch

// Unwrap the recursive transform error:
if err != nil && strings.Contains(err.Error(), "failed to transform internal partial decorator") {
    log.Fatalf("recursive decorator transform failed: %v", err)
}

Prevention

When it happens

Trigger: The synthesized decorator template's inner content contains constructs that themselves fail transformation (e.g. nested unsupported inner usage or bad config). The recursive transform surfaces the failure.

Common situations: Complex with-partial blocks whose body contains additional constructs the transformer rejects; deep nesting of partial decorators; Hugo version regressions in recursive transform handling.

Related errors


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

Appendix: source

Thrown at tpl/tplimpl/templatetransform.go:359

		if err != nil {
			c.err = fmt.Errorf("failed to create internal partial decorator template %q: %w", internalPartialName, err)
			return
		}
		if ti == nil {
			c.err = fmt.Errorf("failed to find internal partial decorator template %q after insertion", internalPartialName)
			return
		}

		cc := newTemplateTransformContext(ti, c.store, c.lookupFn)

		tree, err := c.store.addTransformedTemplateSetTree(ti, innerCopy)
		if err != nil {
			c.err = fmt.Errorf("failed to add internal partial decorator template %q: %w", internalPartialName, err)
			return
		}

		if err := cc.applyTransformationsAndSetReturnWrapper(tree); err != nil {
			c.err = fmt.Errorf("failed to transform internal partial decorator template %q: %w", internalPartialName, err)
			return
		}

	}

	newInner := popPartialDecorator.CopyList()
	ifNode := newInner.Nodes[0].(*parse.IfNode)

	placeholderPipe := ifNode.Pipe.Cmds[0].Args[0].(*parse.PipeNode)

	// Set PLACEHOLDER1 to the unique ID for this partial decorator.
	sn1 := placeholderPipe.Cmds[0].Args[1].(*parse.PipeNode).Cmds[0].Args[0].(*parse.StringNode)
	sn1.Text = innerHash
	sn1.Quoted = fmt.Sprintf("%q", sn1.Text)

	ifNode.ElseList = withNode.List.CopyList()

	newPipe := pushPartialDecorator.CopyList()

View on GitHub (pinned to 52c9bd7908)