{"id":"b6a65f6ac25e689e","repo":"gohugoio/hugo","slug":"max-depth-exceeded-b6a65f","errorCode":null,"errorMessage":"max depth exceeded","messagePattern":"max depth exceeded","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"common/hmaps/params.go","lineNumber":50,"sourceCode":"\n// GetNested does a lower case and nested search in this map.\n// It will return nil if none found.\n// Make all of these methods internal somehow.\nfunc (p Params) GetNested(indices ...string) any {\n\tv, _, _ := getNested(p, indices)\n\treturn v\n}\n\n// SetParams overwrites values in dst with values in src for common or new keys.\n// This is done recursively.\nfunc SetParams(dst, src Params) {\n\tsetParams(dst, src, 0)\n}\n\nfunc setParams(dst, src Params, depth int) {\n\tconst maxDepth = 1000\n\tif depth > maxDepth {\n\t\tpanic(errors.New(\"max depth exceeded\"))\n\t}\n\tfor k, v := range src {\n\t\tvv, found := dst[k]\n\t\tif !found {\n\t\t\tdst[k] = v\n\t\t} else {\n\t\t\tswitch vvv := vv.(type) {\n\t\t\tcase Params:\n\t\t\t\tif pv, ok := v.(Params); ok {\n\t\t\t\t\tsetParams(vvv, pv, depth+1)\n\t\t\t\t} else {\n\t\t\t\t\tdst[k] = v\n\t\t\t\t}\n\t\t\tdefault:\n\t\t\t\tdst[k] = v\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/common/hmaps/params.go#L32-L68","documentation":"hmaps.setParams recursively merges the src Params map into dst. To guard against unbounded recursion it tracks depth and panics with \"max depth exceeded\" once nesting passes 1000 levels (common/hmaps/params.go:50). This is a safety valve: legitimate Hugo config/front matter never nests that deep, so hitting it indicates a cyclic or pathologically deep parameter structure.","triggerScenarios":"SetParams merging Params maps nested more than 1000 levels deep — in practice a Params map that (directly or indirectly) contains itself, or generated config/front matter with absurd nesting, during cascade/param merging.","commonSituations":"Programmatically generated front matter or config with self-referencing map structures; a module/theme mounting that produces cyclic param merges; machine-generated data with runaway nesting fed into cascade or site params.","solutions":["Find the cyclic or extremely deep params structure — inspect recently added front matter, cascade blocks, or generated config for self-reference.","Flatten or break the cycle in the source data; Hugo params should be at most a handful of levels deep.","If the data is machine-generated, add a depth cap or cycle check to the generator."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func depth(m map[string]any, d int) int {\n\tmax := d\n\tfor _, v := range m {\n\t\tif mm, ok := v.(map[string]any); ok {\n\t\t\tif dd := depth(mm, d+1); dd > max { max = dd }\n\t\t}\n\t}\n\treturn max\n}\n// reject or flatten params deeper than the library's limit before passing them in","typeGuard":null,"tryCatchPattern":"if err := hmaps.PrepareParams(m); err != nil {\n\t// params nested too deep — flatten the structure, don't truncate silently\n}","preventionTips":["Keep site/page params shallow (a few levels); deeply nested config is usually a modeling smell.","Never build params structures with cycles or self-references — cycles present as infinite depth.","If ingesting external JSON into params, cap or flatten its nesting at import time."],"tags":["hugo","params","recursion","panic","config"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}