wagoodman/dive · warning

path does not exist: %s

Error message

path does not exist: %s

What it means

Returned (not panicked) by FileTree.GetNode (dive/filetree/file_tree.go:236). GetNode walks the children map segment by segment for a slash-delimited path; the moment a segment is missing from node.Children it returns 'path does not exist: %s'. It is the tree-walk equivalent of a failed map lookup.

Source

Thrown at dive/filetree/file_tree.go:236

				failed = append(failed, NewPathError(node.Path(), ActionRemove, err))
			}
		}
		return nil
	}
	stackErr = upper.VisitDepthChildFirst(graft, nil)
	return failed, stackErr
}

// GetNode fetches a single node when given a slash-delimited string from root ('/') to the desired node (e.g. '/a/node/path')
func (tree *FileTree) GetNode(path string) (*FileNode, error) {
	nodeNames := strings.Split(strings.Trim(path, "/"), "/")
	node := tree.Root
	for _, name := range nodeNames {
		if name == "" {
			continue
		}
		if node.Children[name] == nil {
			return nil, fmt.Errorf("path does not exist: %s", path)
		}
		node = node.Children[name]
	}
	return node, nil
}

// AddPath adds a new node to the tree with the given payload
func (tree *FileTree) AddPath(filepath string, data FileInfo) (*FileNode, []*FileNode, error) {
	filepath = path.Clean(filepath)
	if filepath == "." {
		return nil, nil, fmt.Errorf("cannot add relative path '%s'", filepath)
	}
	nodeNames := strings.Split(strings.Trim(filepath, "/"), "/")
	node := tree.Root
	addedNodes := make([]*FileNode, 0)
	for idx, name := range nodeNames {
		if name == "" {
			continue

View on GitHub (pinned to d6c691947f)

Solutions

  1. Check the path against the stacked/analysis tree, not an individual layer tree
  2. Normalize input first: path.Clean on the query, and remember segments are matched literally
  3. Handle the error as an expected 'not found' rather than a failure - this is a sentinel-style lookup miss
  4. Verify the path actually exists in the image: dive <image> then search for the file in the UI to confirm which tree holds it

Example fix

// before: assuming the node exists
node, _ := tree.GetNode("/etc/nginx/nginx.conf") // nil node + swallowed error -> later nil deref

// after: treat miss as a case
node, err := tree.GetNode(path.Clean(p))
if err != nil {
    return fmt.Errorf("file not present in this tree: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// normalize before lookup
q := path.Clean(p)
if !strings.HasPrefix(q, "/") {
    q = "/" + q
}
node, err := tree.GetNode(q)
if err != nil { /* expected miss */ }

Try / catch

node, err := tree.GetNode(target)
if err != nil {
    if strings.Contains(err.Error(), "path does not exist") {
        // treat as not-found, not a failure
        return nil, nil
    }
    return nil, fmt.Errorf("lookup %q: %w", target, err)
}

Prevention

When it happens

Trigger: Calling GetNode with a path whose first differing segment is absent - e.g. '/etc/nginx' when the tree has no 'etc' child; querying a path that only exists in a different (later) layer before those layers are stacked; typos or non-normalized input ('/etc//nginx' is tolerated by the empty-segment skip, but '/etc/./nginx' is not - '.' is looked up literally).

Common situations: Writing tooling on top of dive's filetree that probes for files by absolute path, then probing a path from a layer that was deleted (whiteout) or that was never added; querying the wrong tree object (per-layer tree instead of the stacked analysis tree).

Related errors


AI-assisted analysis of wagoodman/dive@d6c691947f (2026-08-15). Data as JSON: /api/errors/601214265c2ac442. Report an issue: GitHub.