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

  1. Check the wrapped error for the exact failing operation (assign/derive diff type vs stack range)
  2. Re-pull or rebuild the image to eliminate corrupted layer data, then retry
  3. Simplify reproduction: analyze a single-layer derivative (docker save/squash) to find the offending layer pair
  4. 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

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


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