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
breakView on GitHub (pinned to d6c691947f)
Solutions
- Re-create the archive from the source engine: 'docker save <image> -o img.tar' (or 'podman image save') and retry
- Verify the archive is intact: 'tar -tf img.tar' and confirm every path in manifest.json's Layers array exists inside the tar
- 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
- 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
- Never hand-edit manifest.json or shuffle layer blobs inside a save archive
- Validate downloads (checksums) so truncated saves never reach the parser
- Generate archives exclusively with 'docker save'/'podman image save'
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
- failed to unmarshal manifest: %w
- could not find image manifest
- could not find image config
- unexpected tar file (XHeader): type=%v name=%s
- invalid %s config value, given %q: %v
AI-assisted analysis of wagoodman/dive@d6c691947f (2026-08-15).
Data as JSON: /api/errors/e4a13b5f0cc70516.
Report an issue: GitHub.