{"id":"59825a66bbef044d","repo":"gohugoio/hugo","slug":"maximum-template-call-stack-size-exceeded-in-q","errorCode":null,"errorMessage":"maximum template call stack size exceeded in %q","messagePattern":"maximum template call stack size exceeded in %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"tpl/tplimpl/templatestore.go","lineNumber":541,"sourceCode":"\ttempl := ti.Template\n\n\tparent := tpl.Context.CurrentTemplate.Get(ctx)\n\tvar level int\n\tif parent != nil {\n\t\tlevel = parent.Level + 1\n\t}\n\tcurrentTi := &tpl.CurrentTemplateInfo{\n\t\tParent:                 parent,\n\t\tLevel:                  level,\n\t\tKey:                    key,\n\t\tCurrentTemplateInfoOps: ti,\n\t}\n\n\tctx = tpl.Context.CurrentTemplate.Set(ctx, currentTi)\n\n\tconst levelThreshold = 999\n\tif level > levelThreshold {\n\t\treturn fmt.Errorf(\"maximum template call stack size exceeded in %q\", ti.Filename())\n\t}\n\n\tif t.opts.Metrics != nil {\n\t\tdefer t.opts.Metrics.MeasureSince(templ.Name(), time.Now())\n\t}\n\n\texecErr := t.storeSite.executer.ExecuteWithContext(ctx, ti, wr, data)\n\tif execErr != nil {\n\t\treturn t.addFileContext(ti, \"execute of template failed\", execErr)\n\t}\n\treturn nil\n}\n\nfunc (t *TemplateStore) GetFunc(name string) (reflect.Value, bool) {\n\tv, found := t.storeSite.execHelper.funcs[name]\n\treturn v, found\n}\n","sourceCodeStart":523,"sourceCodeEnd":559,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/tpl/tplimpl/templatestore.go#L523-L559","documentation":"Hugo tracks template nesting depth per execution via `CurrentTemplateInfo.Level` in `TemplateStore.ExecuteWithContextAndKey`. When a template invocation chain exceeds 999 levels, Hugo aborts with this error naming the template file, since it almost certainly indicates infinite recursion between templates/partials rather than legitimate nesting.","triggerScenarios":"A partial that includes itself (directly or via a cycle: A includes B includes A) without a terminating condition; recursive `partial`/`template` calls on nested data structures (e.g. menu trees) whose recursion never bottoms out; a baseof/block cycle.","commonSituations":"Recursive menu or table-of-contents partials missing the base-case check (e.g. forgetting `{{ if .Children }}` before re-invoking); a partial renamed such that it accidentally calls itself instead of a differently-named helper; render hooks that render markdown which re-triggers the same hook.","solutions":["Open the template named in the error and trace its `partial`/`template` calls for a cycle back to itself; add a terminating condition (e.g. only recurse when `.Children` is non-empty).","Pass a depth counter in the partial context (`dict \"depth\" (add .depth 1)`) and stop at a sane limit.","Check render hooks (layouts/_markup/*) that call `.RenderString` or partials which re-enter the same hook."],"exampleFix":"<!-- before: partials/menu.html -->\n{{ range .entries }}{{ partial \"menu.html\" (dict \"entries\" .Children) }}{{ end }}\n<!-- after -->\n{{ range .entries }}{{ with .Children }}{{ partial \"menu.html\" (dict \"entries\" .) }}{{ end }}{{ end }}","handlingStrategy":"validation","validationCode":"{{/* pass an explicit depth guard to recursive partials */}}\n{{ $depth := .depth | default 0 }}\n{{ if lt $depth 50 }}{{ partial \"tree.html\" (dict \"node\" .node \"depth\" (add $depth 1)) }}{{ end }}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add an explicit depth counter to any recursive partial or shortcode and stop before Hugo's stack limit","Never have a template include itself (or a cycle of includes) without a terminating condition","Check that menu/section trees used for recursion are acyclic","Prefer iteration with a stack (slice) over deep template recursion for large trees"],"tags":["hugo","templates","recursion","partials"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}