wagoodman/dive · error

could not find image manifest

Error message

could not find image manifest

What it means

Returned by the docker-archive loader (dive/image/docker/image_archive.go:177) when the tar contains no manifest.json and no file passes the isConfig() heuristic among the *.json entries. Docker-saved archives include manifest.json for compatibility; pure OCI layout archives do not, so dive scans JSON files for a config-looking blob (rootfs/history fields) - if none matches, you get 'could not find image manifest'.

Source

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

			}
		}
	}

	manifestContent, exists := jsonFiles["manifest.json"]
	if exists {
		img.manifest = newManifest(manifestContent)
	} else {
		// manifest.json is not part of the OCI spec, docker includes it for compatibility
		// Provide compatibility by finding the config and using our layerMap
		var configPath string
		for path, content := range jsonFiles {
			if isConfig(content) {
				configPath = path
				break
			}
		}
		if len(configPath) == 0 {
			return img, fmt.Errorf("could not find image manifest")
		}

		var layerPaths []string
		for k := range img.layerMap {
			layerPaths = append(layerPaths, k)
		}
		img.manifest = manifest{
			ConfigPath:    configPath,
			LayerTarPaths: layerPaths,
		}
	}

	configContent, exists := jsonFiles[img.manifest.ConfigPath]
	if !exists {
		return img, fmt.Errorf("could not find image config")
	}

	img.config = newConfig(configContent)

View on GitHub (pinned to d6c691947f)

Solutions

  1. Convert the OCI archive to docker format: skopeo copy oci-archive:app.tar docker-archive:app-docker.tar app:tag, then analyze the converted tar
  2. Or re-save through an engine: docker load/pull the image and docker save it (produces manifest.json)
  3. Check the tar actually lacks manifest.json: tar -tf app.tar | grep manifest.json
  4. Prefer analyzing via the engine (dive docker://<image>) when conversion is awkward

Example fix

# before (OCI-layout tar from kaniko)
dive docker-archive://app-oci.tar   # could not find image manifest

# after
skopeo copy oci-archive:app-oci.tar docker-archive:app.tar:app:ci
dive docker-archive://app.tar
Defensive patterns

Strategy: fallback

Validate before calling

// detect OCI-only archives before analysis
func hasDockerManifest(tarPath string) bool {
    f, err := os.Open(tarPath)
    if err != nil {
        return false
    }
    defer f.Close()
    tr := tar.NewReader(f)
    for {
        hdr, err := tr.Next()
        if err != nil {
            return false
        }
        if filepath.Base(hdr.Name) == "manifest.json" {
            return true
        }
    }
}

if !hasDockerManifest(p) {
    // convert or go through an engine instead of failing later
}

Try / catch

img, err := resolver.Fetch(ctx, "docker-archive://"+p)
if err != nil && strings.Contains(err.Error(), "could not find image manifest") {
    // fallback: convert OCI -> docker archive with skopeo
    _ = exec.Command("skopeo", "copy", "oci-archive:"+p, "docker-archive:"+p+".docker.tar:tmp:ci").Run()
    img, err = resolver2.Fetch(ctx, "docker-archive://"+p+".docker.tar")
}
if err != nil {
    return err
}

Prevention

When it happens

Trigger: Loading an OCI image layout (as produced by crane/kaniko/skopeo copy dir form or registry extraction) that lacks manifest.json and whose config blob is not discoverable by the heuristic; archives repacked by tools that drop or rename JSON metadata; truncated saves missing the manifest entry.

Common situations: CI artifacts built with buildkit/kaniko exported as OCI tars, then analyzed with dive without conversion; images copied out of registries with skopeo in OCI format; hand-modified tarballs.

Related errors


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