gohugoio/hugo · error
text is already rendered, repeating it may cause infinite…
Error message
text is already rendered, repeating it may cause infinite recursion
What it means
RenderString inspects its content argument and rejects values that are already pre-rendered HTML (the internal hstring.HTML type), because re-rendering already-rendered content can loop infinitely. Passing .Content, .Summary, or another template.HTML value triggers this guard.
Solutions
- Do not pass .Content/.Summary (already-rendered) to RenderString; use them directly.
- Pass the raw source string instead of rendered HTML.
- For plain string manipulation on rendered content, use string functions rather than RenderString.
Example fix
// before
{{ .RenderString .Content }}
// after
{{ .Content }} Defensive patterns
Strategy: validation
Validate before calling
// Reject already-rendered HTML input to RenderString
if _, ok := arg.(hstring.HTML); ok {
return errors.New("input is already rendered; pass raw source instead")
}
// templates: never pass .Content/.Summary to RenderString Type guard
func isRawString(v any) bool {
switch v.(type) {
case string, []byte: return true
}
return false
} Prevention
- Pass raw source strings to RenderString, never .Content/.Summary.
- Use .Content directly when you already have rendered HTML.
- Avoid nesting RenderString calls on rendered output.
When it happens
Trigger: {{ .RenderString .Content }} or feeding any already-rendered HTML (template.HTML / hstring.HTML) into RenderString.
Common situations: Nesting RenderString on content that Hugo already rendered; passing .Summary or .Content where raw source was intended.
Related errors
- first argument must be a map
- want 1 or 2 arguments
- argument must be a slice
- arguments must be slices or arrays
- arguments to complement must be slices or arrays
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/cf3e609e957a5b5e.
Report an issue: GitHub.
Appendix: source
Thrown at hugolib/page__content.go:912
m, ok := args[0].(map[string]any)
if !ok {
return "", errors.New("first argument must be a map")
}
if err := mapstructure.WeakDecode(m, &opts); err != nil {
return "", fmt.Errorf("failed to decode options: %w", err)
}
if opts.Markup != "" {
opts.Markup = markup.ResolveMarkup(opts.Markup)
}
}
contentToRenderv := args[sidx]
if _, ok := contentToRenderv.(hstring.HTML); ok {
// This content is already rendered, this is potentially
// a infinite recursion.
return "", errors.New("text is already rendered, repeating it may cause infinite recursion")
}
var err error
contentToRender, err = cast.ToStringE(contentToRenderv)
if err != nil {
return "", err
}
if err = pco.initRenderHooks(); err != nil {
return "", err
}
conv := pco.po.p.getContentConverter()
if opts.Markup != "" && opts.Markup != pco.po.p.m.pageConfigSource.ContentMediaType.SubType {
var err error
conv, err = pco.po.p.m.newContentConverter(pco.po.p, opts.Markup)
if err != nil {View on GitHub (pinned to 52c9bd7908)