gohugoio/hugo · critical
max depth exceeded
Error message
max depth exceeded
What it means
A panic raised by defaultConfigProvider.WalkParams when recursively walking the site's params/config tree exceeds 1000 nested levels. It is a guard against unbounded recursion — a legitimate Hugo config never approaches this depth, so hitting it almost always means the params tree contains a cycle or pathologically deep nesting.
Source
Thrown at config/defaultConfigProvider.go:252
}
func (c *defaultConfigProvider) Keys() []string {
c.mu.RLock()
defer c.mu.RUnlock()
var keys []string
for k := range c.root {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
func (c *defaultConfigProvider) WalkParams(walkFn func(params ...hmaps.KeyParams) bool) {
maxDepth := 1000
var walk func(depth int, params ...hmaps.KeyParams)
walk = func(depth int, params ...hmaps.KeyParams) {
if depth > maxDepth {
panic(errors.New("max depth exceeded"))
}
if walkFn(params...) {
return
}
p1 := params[len(params)-1]
i := len(params)
for k, v := range p1.Params {
if p2, ok := v.(hmaps.Params); ok {
paramsplus1 := make([]hmaps.KeyParams, i+1)
copy(paramsplus1, params)
paramsplus1[i] = hmaps.KeyParams{Key: k, Params: p2}
walk(depth+1, paramsplus1...)
}
}
}
walk(0, hmaps.KeyParams{Key: "", Params: c.root})
}
View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Inspect site params for cyclic or absurdly deep nesting — especially any generated/imported config; flatten or break the cycle.
- Bisect by removing config mounts/themes/modules until the panic disappears to locate the offending source.
- If the params are reasonable and the panic persists, report it as a Hugo bug with a minimal reproducer, since 1000 levels indicates an internal cycle.
Defensive patterns
Strategy: validation
Validate before calling
// Guard against absurdly deep nesting before handing maps to the config provider
func depth(m map[string]any, d int) int {
max := d
for _, v := range m {
if mm, ok := v.(maps.Params); ok {
if dd := depth(mm, d+1); dd > max { max = dd }
}
}
return max
}
if depth(params, 0) > 32 { return errors.New("config nesting too deep — flatten your params") } Try / catch
if err := provider.SetDefaults(params); err != nil {
if strings.Contains(err.Error(), "max depth exceeded") {
// config maps nested beyond the provider's recursion limit — usually a self-referencing or generated structure
}
return err
} Prevention
- Keep params nesting shallow (a handful of levels); deep trees usually mean generated or accidentally self-referential config
- If you generate config programmatically, assert its depth in your generator's tests
- Don't merge a config map into itself (aliasing creates effectively infinite depth)
When it happens
Trigger: WalkParams recursing more than 1000 map levels deep — a params map that (directly or via module/theme config merging or programmatic mutation) contains a reference cycle, or genuinely 1000+ levels of nested maps in config/params.
Common situations: Generated or machine-produced config/data injected into site params with self-referencing structures; extreme auto-generated nesting in params files; a Hugo bug where config merging creates a cycle — worth reporting upstream since hand-written configs cannot realistically trigger this.
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/b38ec3a5382ca394.json.
Report an issue: GitHub ↗.