wagoodman/dive · error

could not find '%s' in parsed layers

Error message

could not find '%s' in parsed layers

What it means

ToImage() builds the image by looking up every layer tar path listed in manifest.json inside the layerMap that was previously parsed from the archive. If a manifest entry (e.g. 'blobs/sha256/...' or 'layer/layer.tar') has no matching key in layerMap, the manifest and the actually-parsed archive contents disagree and dive refuses to construct a half-built image.

Source

Thrown at dive/image/docker/image_archive.go:260

			return nil, fmt.Errorf("unexpected tar file (XHeader): type=%v name=%s", header.Typeflag, name)
		default:
			files = append(files, filetree.NewFileInfoFromTarHeader(tarReader, header, name))
		}
	}
	return files, nil
}

func (img *ImageArchive) ToImage(id string) (*image.Image, error) {
	trees := make([]*filetree.FileTree, 0)

	// build the content tree
	for _, treeName := range img.manifest.LayerTarPaths {
		tr, exists := img.layerMap[treeName]
		if exists {
			trees = append(trees, tr)
			continue
		}
		return nil, fmt.Errorf("could not find '%s' in parsed layers", treeName)
	}

	// build the layers array
	layers := make([]*image.Layer, 0)

	// note that the engineResolver config stores images in reverse chronological order, so iterate backwards through layers
	// as you iterate chronologically through history (ignoring history items that have no layer contents)
	// Note: history is not required metadata in a docker image!
	histIdx := 0
	for idx, tree := range trees {
		// ignore empty layers, we are only observing layers with content
		historyObj := historyEntry{
			CreatedBy: "(missing)",
		}
		for nextHistIdx := histIdx; nextHistIdx < len(img.config.History); nextHistIdx++ {
			if !img.config.History[nextHistIdx].EmptyLayer {
				histIdx = nextHistIdx
				break

View on GitHub (pinned to d6c691947f)

Solutions

  1. Re-create the archive from the source engine: 'docker save <image> -o img.tar' (or 'podman image save') and retry
  2. Verify the archive is intact: 'tar -tf img.tar' and confirm every path in manifest.json's Layers array exists inside the tar
  3. Check for path-format drift: manifest entries must match the tar member names exactly (no extra './', no renamed blobs); rebuild the tar so they align
  4. If the archive is OCI-layout rather than docker-save format, convert it first (e.g. 'skopeo copy oci:/path docker-archive:img.tar')

Example fix

# before
package main
import "github.com/wagoodman/dive/image/docker"

img, _ := docker.NewImageArchive(f)
image, err := img.ToImage("id") // could not find 'blobs/sha256/...' in parsed layers

# after: validate manifest paths against tar members first
tar -tf img.tar   # confirm each manifest.json "Layers" entry is a member
# then re-save if missing:
docker save myimg:latest -o img.tar
Defensive patterns

Strategy: validation

Validate before calling

// Verify every manifest Layers entry exists as a tar member before calling ToImage.
func validateLayerPaths(archiveTar io.Reader) error {
    tr := tar.NewReader(archiveTar)
    members := map[string]bool{}
    for {
        h, err := tr.Next()
        if err == io.EOF { break }
        if err != nil { return err }
        members[path.Clean(h.Name)] = true
    }
    m, err := readManifest(archiveTar) // parse manifest.json separately
    if err != nil { return err }
    for _, p := range m.LayerTarPaths {
        if !members[path.Clean(p)] { return fmt.Errorf("manifest layer missing from archive: %s", p) }
    }
    return nil
}

Try / catch

if _, err := imgArchive.ToImage(id); err != nil {
    if strings.Contains(err.Error(), "in parsed layers") {
        // manifest/archive mismatch: re-save the image and rebuild the archive
    }
    return err
}

Prevention

When it happens

Trigger: Calling ImageArchive.ToImage after NewImageArchive on an archive where manifest.json's Layers[] references paths that were not present (or were skipped) when the archive tar was walked: truncated or corrupt 'docker save' output, archives where layer file paths differ from the manifest keys (leading './', absolute paths, different casing), or OCI-layout archives whose manifest paths don't match docker-style layer paths the parser expected.

Common situations: Corrupted/partially downloaded image tar; archives produced by a different tool (skopeo/copied OCI dirs) whose manifest.json layer paths use a different prefix than the files in the tar; intermixing layers from two archives; disk-full during 'docker save'.

Related errors


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