gohugoio/hugo · critical
Transform must be performed with NoShift=true
Error message
Transform must be performed with NoShift=true
What it means
A panic in NodeShiftTreeWalker.Walk (hugolib/doctree/nodeshifttree.go:565) when a Transform callback is set but NoShift is false. Transform replaces raw tree nodes; shifting them mid-walk would corrupt iteration, so Transform is only permitted with NoShift=true.
Source
Thrown at hugolib/doctree/nodeshifttree.go:565
if r.NoShift {
t = v
} else {
var ok bool
t, ok = r.toT(r.Tree, v)
if !ok {
return radix.WalkContinue, zero, nil
}
}
var (
ns NodeTransformState
t2 T
)
if r.IncludeFilter != nil && !r.IncludeFilter(s, t) {
return radix.WalkContinue, zero, nil
}
if r.Transform != nil {
if !r.NoShift {
panic("Transform must be performed with NoShift=true")
}
var err error
ns, err = func() (ns NodeTransformState, err error) {
t2, ns, err = r.Transform(s, t)
if ns >= NodeTransformStateSkip || err != nil {
return
}
switch ns {
case NodeTransformStateReplaced:
case NodeTransformStateDeleted:
// Delay delete until after the walk.
deletes = append(deletes, s)
ns = NodeTransformStateSkip
}
return
}()
if ns == NodeTransformStateTerminate || err != nil {View on GitHub (pinned to 52c9bd7908)
Solutions
- Set walker.NoShift = true whenever you set walker.Transform
- Split into two passes: a shifted read pass, then a NoShift transform pass
- If you only need to inspect nodes, use Handle instead of Transform
Example fix
// before
w := &doctree.NodeShiftTreeWalker[contentNode]{
Tree: tree,
Transform: transformFn,
}
// after
w := &doctree.NodeShiftTreeWalker[contentNode]{
Tree: tree,
Transform: transformFn,
NoShift: true,
} Defensive patterns
Strategy: validation
Validate before calling
if walker.Transform != nil && !walker.NoShift {
return errors.New("set NoShift=true when using Transform")
} Prevention
- Set NoShift=true whenever Transform is set
- Separate read (shift) and mutate (no-shift) into distinct passes
- Use Handle for read-only inspection
When it happens
Trigger: Setting walker.Transform != nil and leaving walker.NoShift at its default (false).
Common situations: Writing a custom walk that mutates nodes but forgetting to set NoShift; adapting a read-only walker into a transform walker.
Related errors
- Handle cannot replace nodes in the tree, use Transform for t
- Shifter is required
- transformerRaw is required
- DeleteFunc: unknown type %T
- Insert: unknown type %T
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/451587ffe759560b.
Report an issue: GitHub.