wagoodman/dive · error
failed to build tree: %w
Error message
failed to build tree: %w
What it means
Inside the filetree Comparer's get(), after stacking the bottom tree range, each top-layer tree is compared and merged via CompareAndMark; any error from that step is wrapped as 'failed to build tree'. This is the comparer's generic failure for being unable to merge an upper layer onto the stacked lower tree — typically from AssignDiffType/deriveDiffType rejecting an operation on inconsistent tree state, or the stack step failing upstream.
Source
Thrown at dive/filetree/comparer.go:79
value, pathErrors, err := cmp.get(key)
if err != nil {
return nil, err
}
cmp.trees[key] = value
cmp.pathErrors[key] = pathErrors
return value, nil
}
func (cmp *Comparer) get(key TreeIndexKey) (*FileTree, []PathError, error) {
newTree, pathErrors, err := StackTreeRange(cmp.refTrees, key.bottomTreeStart, key.bottomTreeStop)
if err != nil {
return nil, nil, err
}
for idx := key.topTreeStart; idx <= key.topTreeStop; idx++ {
markPathErrors, err := newTree.CompareAndMark(cmp.refTrees[idx])
pathErrors = append(pathErrors, markPathErrors...)
if err != nil {
return nil, nil, fmt.Errorf("failed to build tree: %w", err)
}
}
return newTree, pathErrors, nil
}
// case 1: layer compare (top tree SIZE is fixed (BUT floats forward), Bottom tree SIZE changes)
func (cmp *Comparer) NaturalIndexes() <-chan TreeIndexKey {
indexes := make(chan TreeIndexKey)
go func() {
defer close(indexes)
var bottomTreeStart, bottomTreeStop, topTreeStart, topTreeStop int
for selectIdx := 0; selectIdx < len(cmp.refTrees); selectIdx++ {
bottomTreeStart = 0
topTreeStop = selectIdx
View on GitHub (pinned to d6c691947f)
Solutions
- Check the wrapped error for the exact failing operation (assign/derive diff type vs stack range)
- Re-pull or rebuild the image to eliminate corrupted layer data, then retry
- Simplify reproduction: analyze a single-layer derivative (docker save/squash) to find the offending layer pair
- Report upstream with the image reference and full error chain
Defensive patterns
Strategy: try-catch
Validate before calling
// programmatic use: validate key bounds before GetTree
n := len(cmp.RefTrees)
if key.bottomTreeStart < 0 || key.bottomTreeStop >= n || key.topTreeStop >= n {
return errors.New("tree index key out of range")
} Try / catch
tree, err := cmp.GetTree(key)
if err != nil {
return nil, fmt.Errorf("build tree %s: %w", key, err) // key.String() aids debugging
} Prevention
- Use the comparer's own index generators (NaturalIndexes/AggregatedIndexes) instead of hand-built keys
- Validate refTrees slices are non-empty and consistent before comparing
- Warm the cache at startup to surface bad layers once, early
When it happens
Trigger: newTree.CompareAndMark(cmp.refTrees[idx]) returning non-nil for any idx in [topTreeStart, topTreeStop]: graft-time AddPath failures are captured as PathErrors (non-fatal), but AssignDiffType or deriveDiffType errors abort the build. Occurs during GetTree cache misses — i.e. first render of a layer selection or BuildCache warm-up.
Common situations: Images with unusual whiteout semantics (deleting paths absent from lower layers in conflicting ways), non-standard layer payloads from niche builders, corrupted layers from a bad pull, or programmatic misuse of NewTreeIndexKey with out-of-range bounds causing refTrees[idx] lookups on inconsistent ranges.
Related errors
- unable to fetch layer tree from cache: %w
- path error at layer index %s: %s
- file tree has path errors (use '--ignore-errors' to attempt
- notifyOnViewOptionChangeListeners error: %w
- unable to setup tree controller: %w
AI-assisted analysis of wagoodman/dive@d6c691947f (2026-08-15).
Data as JSON: /api/errors/5740558929c4a028.
Report an issue: GitHub.