{"record":{"id":"fd616d2448742835","repo":"wagoodman/dive","slug":"could-not-add-child-node-s-path-s","errorCode":null,"errorMessage":"could not add child node: '%s' (path:'%s')","messagePattern":"could not add child node: '(.+?)' \\(path:'(.+?)'\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"dive/filetree/file_tree.go","lineNumber":272,"sourceCode":"\t\t\tcontinue\n\t\t}\n\t\t// find or create node\n\t\tif node.Children[name] != nil {\n\t\t\tnode = node.Children[name]\n\t\t} else {\n\t\t\t// don't add paths that should be deleted\n\t\t\tif strings.HasPrefix(name, doubleWhiteoutPrefix) {\n\t\t\t\treturn nil, addedNodes, nil\n\t\t\t}\n\n\t\t\t// don't attach the payload. The payload is destined for the\n\t\t\t// Path's end node, not any intermediary node.\n\t\t\tnode = node.AddChild(name, FileInfo{})\n\t\t\taddedNodes = append(addedNodes, node)\n\n\t\t\tif node == nil {\n\t\t\t\t// the child could not be added\n\t\t\t\treturn node, addedNodes, fmt.Errorf(\"could not add child node: '%s' (path:'%s')\", name, filepath)\n\t\t\t}\n\t\t}\n\n\t\t// attach payload to the last specified node\n\t\tif idx == len(nodeNames)-1 {\n\t\t\tnode.Data.FileInfo = data\n\t\t}\n\t}\n\treturn node, addedNodes, nil\n}\n\n// RemovePath removes a node from the tree given its path.\nfunc (tree *FileTree) RemovePath(path string) error {\n\tnode, err := tree.GetNode(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn node.Remove()","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/wagoodman/dive/blob/d6c691947f8fda635c952a17ee3b7555379d58f0/dive/filetree/file_tree.go#L254-L290","documentation":"Returned by FileTree.AddPath (dive/filetree/file_tree.go:272) when FileNode.AddChild returns nil for an intermediary path segment. In this version AddChild (file_node.go:90) returns nil only for names with the double-whiteout prefix (.wh..wh..), which AddPath itself already screens before calling AddChild - so the branch is defensive/unreachable in stock flows. Note the code also appends the nil node to addedNodes before checking, so callers see a nil entry in the slice too.","triggerScenarios":"Adding a path containing a segment named '.wh..wh..-*' that evades the HasPrefix check in AddPath (e.g. after path.Clean normalization differences), or a fork of AddChild that can return nil for invalid payloads.","commonSituations":"Almost never fires upstream. Appears in forks/tests that inject failing AddChild behavior or hand-craft whiteout-prefixed path segments.","solutions":["Sanitize whiteout-prefixed segments before calling AddPath: strip or reject names starting with '.wh.'","Check both the error and for nil entries in returned addedNodes if you drive this API directly","If you maintain a fork, make AddChild's nil conditions explicit and align them with AddPath's prefix filter"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// strip whiteout-style segments before driving AddPath\nfunc safeSegments(p string) bool {\n    for _, seg := range strings.Split(strings.Trim(p, \"/\"), \"/\") {\n        if strings.HasPrefix(seg, \".wh.\") {\n            return false\n        }\n    }\n    return true\n}","typeGuard":null,"tryCatchPattern":"node, added, err := tree.AddPath(p, data)\nif err != nil && strings.Contains(err.Error(), \"could not add child node\") {\n    log.Printf(\"dropping whiteout-ish path %s\", p)\n    err = nil // this branch is defensive-only upstream\n}","preventionTips":["Sanitize '.wh.'-prefixed names before tree construction","Never hand-construct nodes bypassing AddPath/AddChild contracts","Nil-check entries in returned addedNodes if you consume that slice"],"tags":["filetree","whiteout","defensive-code","unreachable"],"backgroundTag":null,"analyzedSha":"d6c691947f8fda635c952a17ee3b7555379d58f0","analyzedAt":"2026-08-15T09:42:35.293Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}