gohugoio/hugo · critical
max depth exceeded
Error message
max depth exceeded
What it means
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.
Source
Thrown at common/hmaps/params.go:50
// GetNested does a lower case and nested search in this map.
// It will return nil if none found.
// Make all of these methods internal somehow.
func (p Params) GetNested(indices ...string) any {
v, _, _ := getNested(p, indices)
return v
}
// SetParams overwrites values in dst with values in src for common or new keys.
// This is done recursively.
func SetParams(dst, src Params) {
setParams(dst, src, 0)
}
func setParams(dst, src Params, depth int) {
const maxDepth = 1000
if depth > maxDepth {
panic(errors.New("max depth exceeded"))
}
for k, v := range src {
vv, found := dst[k]
if !found {
dst[k] = v
} else {
switch vvv := vv.(type) {
case Params:
if pv, ok := v.(Params); ok {
setParams(vvv, pv, depth+1)
} else {
dst[k] = v
}
default:
dst[k] = v
}
}
}View on GitHub ↗ (pinned to 8a468df065)
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.
Defensive patterns
Strategy: validation
Validate before calling
func depth(m map[string]any, d int) int {
max := d
for _, v := range m {
if mm, ok := v.(map[string]any); ok {
if dd := depth(mm, d+1); dd > max { max = dd }
}
}
return max
}
// reject or flatten params deeper than the library's limit before passing them in Try / catch
if err := hmaps.PrepareParams(m); err != nil {
// params nested too deep — flatten the structure, don't truncate silently
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- max depth exceeded
- failed to load config: %v
- language %q not found
- unsupported format: %q
- failed to create workingDir: %w
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/b6a65f6ac25e689e.json.
Report an issue: GitHub ↗.