{"record":{"id":"451587ffe759560b","repo":"gohugoio/hugo","slug":"transform-must-be-performed-with-noshift-true","errorCode":null,"errorMessage":"Transform must be performed with NoShift=true","messagePattern":"Transform must be performed with NoShift=true","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hugolib/doctree/nodeshifttree.go","lineNumber":565,"sourceCode":"\t\t\tif r.NoShift {\n\t\t\t\tt = v\n\t\t\t} else {\n\t\t\t\tvar ok bool\n\t\t\t\tt, ok = r.toT(r.Tree, v)\n\t\t\t\tif !ok {\n\t\t\t\t\treturn radix.WalkContinue, zero, nil\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar (\n\t\t\t\tns NodeTransformState\n\t\t\t\tt2 T\n\t\t\t)\n\t\t\tif r.IncludeFilter != nil && !r.IncludeFilter(s, t) {\n\t\t\t\treturn radix.WalkContinue, zero, nil\n\t\t\t}\n\t\t\tif r.Transform != nil {\n\t\t\t\tif !r.NoShift {\n\t\t\t\t\tpanic(\"Transform must be performed with NoShift=true\")\n\t\t\t\t}\n\t\t\t\tvar err error\n\t\t\t\tns, err = func() (ns NodeTransformState, err error) {\n\t\t\t\t\tt2, ns, err = r.Transform(s, t)\n\t\t\t\t\tif ns >= NodeTransformStateSkip || err != nil {\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tswitch ns {\n\t\t\t\t\tcase NodeTransformStateReplaced:\n\t\t\t\t\tcase NodeTransformStateDeleted:\n\t\t\t\t\t\t// Delay delete until after the walk.\n\t\t\t\t\t\tdeletes = append(deletes, s)\n\t\t\t\t\t\tns = NodeTransformStateSkip\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}()\n\n\t\t\t\tif ns == NodeTransformStateTerminate || err != nil {","sourceCodeStart":547,"sourceCodeEnd":583,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/hugolib/doctree/nodeshifttree.go#L547-L583","documentation":"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.","triggerScenarios":"Setting walker.Transform != nil and leaving walker.NoShift at its default (false).","commonSituations":"Writing a custom walk that mutates nodes but forgetting to set NoShift; adapting a read-only walker into a transform walker.","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"],"exampleFix":"// before\nw := &doctree.NodeShiftTreeWalker[contentNode]{\n    Tree: tree,\n    Transform: transformFn,\n}\n// after\nw := &doctree.NodeShiftTreeWalker[contentNode]{\n    Tree: tree,\n    Transform: transformFn,\n    NoShift: true,\n}","handlingStrategy":"validation","validationCode":"if walker.Transform != nil && !walker.NoShift {\n    return errors.New(\"set NoShift=true when using Transform\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set NoShift=true whenever Transform is set","Separate read (shift) and mutate (no-shift) into distinct passes","Use Handle for read-only inspection"],"tags":["doctree","walker","api-misuse","panic"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}