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

  1. Do not pass .Content/.Summary (already-rendered) to RenderString; use them directly.
  2. Pass the raw source string instead of rendered HTML.
  3. 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

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


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)