{"record":{"id":"567160f65faf34a4","repo":"wagoodman/dive","slug":"unable-to-propagate-layer-tree-w","errorCode":null,"errorMessage":"unable to propagate layer tree: %w","messagePattern":"unable to propagate layer tree: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/dive/cli/internal/ui/v1/viewmodel/filetree.go","lineNumber":128,"sourceCode":"\tif topTreeStop > len(vm.RefTrees)-1 {\n\t\treturn fmt.Errorf(\"invalid layer index given: %d of %d\", topTreeStop, len(vm.RefTrees)-1)\n\t}\n\tnewTree, err := vm.comparer.GetTree(filetree.NewTreeIndexKey(bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to fetch layer tree from cache: %w\", err)\n\t}\n\n\t// preserve vm state on copy\n\tvisitor := func(node *filetree.FileNode) error {\n\t\tnewNode, err := newTree.GetNode(node.Path())\n\t\tif err == nil {\n\t\t\tnewNode.Data.ViewInfo = node.Data.ViewInfo\n\t\t}\n\t\treturn nil\n\t}\n\terr = vm.ModelTree.VisitDepthChildFirst(visitor, nil)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to propagate layer tree: %w\", err)\n\t}\n\n\tvm.ModelTree = newTree\n\treturn nil\n}\n\n// CursorUp performs the internal view's buffer adjustments on cursor up. Note: this is independent of the gocui buffer.\nfunc (vm *FileTreeViewModel) CursorUp() bool {\n\tif vm.TreeIndex <= 0 {\n\t\treturn false\n\t}\n\tvm.TreeIndex--\n\tif vm.TreeIndex < vm.bufferIndexLowerBound {\n\t\tvm.bufferIndexLowerBound--\n\t}\n\tif vm.bufferIndex > 0 {\n\t\tvm.bufferIndex--\n\t}","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/wagoodman/dive/blob/d6c691947f8fda635c952a17ee3b7555379d58f0/cmd/dive/cli/internal/ui/v1/viewmodel/filetree.go#L110-L146","documentation":"SetTreeByLayer wraps errors from vm.ModelTree.VisitDepthChildFirst while copying per-node ViewInfo (collapse/hidden state) onto the freshly stacked tree. The visitor in this code path always returns nil, so the wrapped error can only come from the traversal machinery itself — in practice this is a defensive, near-unreachable wrapper.","triggerScenarios":"VisitDepthChildFirst returning an error while walking the old model tree; the closure never errors, so this requires a tree in a structurally invalid state (nil root, corrupted parent/child links) or modified traversal code in a fork.","commonSituations":"Practically unseen in stock dive; possible in forks that add fallible logic to the state-copy visitor; memory corruption or concurrent mutation of ModelTree from another goroutine could theoretically trip the walker.","solutions":["If in stock dive, capture the full error chain and report upstream — it indicates corrupted tree state","Audit forks for changes to the visitor closure (it must keep returning nil for benign misses)","Ensure no goroutine mutates vm.ModelTree concurrently with layer switches","Re-run analysis on the image to rebuild trees from scratch"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := vm.ModelTree.VisitDepthChildFirst(visitor, nil); err != nil {\n    return fmt.Errorf(\"unable to propagate layer tree: %w\", err)\n}","preventionTips":["Keep visitor closures nil-error in stock paths","Don't mutate ModelTree from other goroutines","If forking, add fallible ops only after auditing traversal order"],"tags":["filetree","traversal","defensive","concurrency"],"backgroundTag":null,"analyzedSha":"d6c691947f8fda635c952a17ee3b7555379d58f0","analyzedAt":"2026-08-15T09:42:35.293Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}