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

  1. Find the cyclic or extremely deep params structure — inspect recently added front matter, cascade blocks, or generated config for self-reference.
  2. Flatten or break the cycle in the source data; Hugo params should be at most a handful of levels deep.
  3. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/b6a65f6ac25e689e.json. Report an issue: GitHub ↗.