{"record":{"id":"cf3e609e957a5b5e","repo":"gohugoio/hugo","slug":"text-is-already-rendered-repeating-it-may-cause-i","errorCode":null,"errorMessage":"text is already rendered, repeating it may cause infinite recursion","messagePattern":"text is already rendered, repeating it may cause infinite recursion","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hugolib/page__content.go","lineNumber":912,"sourceCode":"\t\tm, ok := args[0].(map[string]any)\n\t\tif !ok {\n\t\t\treturn \"\", errors.New(\"first argument must be a map\")\n\t\t}\n\n\t\tif err := mapstructure.WeakDecode(m, &opts); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"failed to decode options: %w\", err)\n\t\t}\n\t\tif opts.Markup != \"\" {\n\t\t\topts.Markup = markup.ResolveMarkup(opts.Markup)\n\t\t}\n\t}\n\n\tcontentToRenderv := args[sidx]\n\n\tif _, ok := contentToRenderv.(hstring.HTML); ok {\n\t\t// This content is already rendered, this is potentially\n\t\t// a infinite recursion.\n\t\treturn \"\", errors.New(\"text is already rendered, repeating it may cause infinite recursion\")\n\t}\n\n\tvar err error\n\tcontentToRender, err = cast.ToStringE(contentToRenderv)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err = pco.initRenderHooks(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tconv := pco.po.p.getContentConverter()\n\n\tif opts.Markup != \"\" && opts.Markup != pco.po.p.m.pageConfigSource.ContentMediaType.SubType {\n\t\tvar err error\n\t\tconv, err = pco.po.p.m.newContentConverter(pco.po.p, opts.Markup)\n\t\tif err != nil {","sourceCodeStart":894,"sourceCodeEnd":930,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/hugolib/page__content.go#L894-L930","documentation":"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.","triggerScenarios":"{{ .RenderString .Content }} or feeding any already-rendered HTML (template.HTML / hstring.HTML) into RenderString.","commonSituations":"Nesting RenderString on content that Hugo already rendered; passing .Summary or .Content where raw source was intended.","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."],"exampleFix":"// before\n{{ .RenderString .Content }}\n// after\n{{ .Content }}","handlingStrategy":"validation","validationCode":"// Reject already-rendered HTML input to RenderString\nif _, ok := arg.(hstring.HTML); ok {\n    return errors.New(\"input is already rendered; pass raw source instead\")\n}\n// templates: never pass .Content/.Summary to RenderString","typeGuard":"func isRawString(v any) bool {\n    switch v.(type) {\n    case string, []byte: return true\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["hugo","template","renderstring","recursion"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}