gohugoio/hugo · critical

Handle cannot replace nodes in the tree, use Transform for t

Error message

Handle cannot replace nodes in the tree, use Transform for that

What it means

A panic in NodeShiftTreeWalker.Walk (hugolib/doctree/nodeshifttree.go:596) when the Handle callback returns a WalkFlag with the Set bit (radix.WalkSet). Replacing nodes is the exclusive job of Transform; Handle is read-only with respect to node replacement.

Source

Thrown at hugolib/doctree/nodeshifttree.go:596

						ns = NodeTransformStateSkip
					}
					return
				}()

				if ns == NodeTransformStateTerminate || err != nil {
					return radix.WalkStop, zero, err
				}

				if ns == NodeTransformStateSkip {
					return radix.WalkContinue, zero, nil
				}

			}

			if r.Handle != nil {
				f, err := r.Handle(s, t)
				if f.ShouldSet() {
					panic("Handle cannot replace nodes in the tree, use Transform for that")
				}
				if f.ShouldStop() || err != nil {
					return f, zero, err
				}
			}
			if ns == NodeTransformStateTerminate {
				return radix.WalkStop, zero, nil
			}
			if ns == NodeTransformStateReplaced {
				return radix.WalkSet | radix.WalkContinue, t2, nil
			}
			return radix.WalkContinue, zero, nil
		}

		handle := &walkHandler[T]{
			r:      r,
			handle: handleV,
		}

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Move node-replacement logic into Transform and set NoShift=true
  2. Have Handle return only WalkContinue/WalkStop without WalkSet

Example fix

// before
Handle: func(s string, v contentNode) (radix.WalkFlag, error) {
    return radix.WalkSet | radix.WalkContinue, nil
}
// after
Handle: func(s string, v contentNode) (radix.WalkFlag, error) {
    return radix.WalkContinue, nil
}
Defensive patterns

Strategy: validation

Validate before calling

// Inside a Handle callback, never return WalkSet.
return radix.WalkContinue, nil

Prevention

When it happens

Trigger: A Handle callback returns radix.WalkSet | radix.WalkContinue, attempting to replace the current node.

Common situations: Copying a WalkFn that returns WalkSet into Handle instead of Transform; misunderstanding the Handle/Transform split.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/e28686b0f03c29c2. Report an issue: GitHub.