containerd/containerd · error

image config %q not found

Error message

image config %q not found

What it means

ImportIndex builds a schema2 manifest for each entry in manifest.json and looks up the referenced config file among the ingested blobs. The manifest's Config path did not match any file entry in the tar, so the config blob is unavailable. This indicates the docker-save archive is internally inconsistent.

Source

Thrown at core/images/archive/importer.go:166

	}

	for name, linkname := range symlinks {
		desc, ok := blobs[linkname]
		if !ok {
			return ocispec.Descriptor{}, fmt.Errorf("no target for symlink layer from %q to %q", name, linkname)
		}
		blobs[name] = desc
	}

	idx := ocispec.Index{
		Versioned: specs.Versioned{
			SchemaVersion: 2,
		},
	}
	for _, mfst := range mfsts {
		config, ok := blobs[mfst.Config]
		if !ok {
			return ocispec.Descriptor{}, fmt.Errorf("image config %q not found", mfst.Config)
		}
		config.MediaType = images.MediaTypeDockerSchema2Config

		layers, err := resolveLayers(ctx, store, mfst.Layers, blobs, iopts.compress)
		if err != nil {
			return ocispec.Descriptor{}, fmt.Errorf("failed to resolve layers: %w", err)
		}

		manifest := struct {
			SchemaVersion int                  `json:"schemaVersion"`
			MediaType     string               `json:"mediaType"`
			Config        ocispec.Descriptor   `json:"config"`
			Layers        []ocispec.Descriptor `json:"layers"`
		}{
			SchemaVersion: 2,
			MediaType:     images.MediaTypeDockerSchema2Manifest,
			Config:        config,
			Layers:        layers,

View on GitHub (pinned to 4246446a2b)

Solutions

  1. Re-run `docker save -o image.tar <image>` to regenerate a self-consistent archive
  2. Cross-check `tar tf image.tar` against the Config paths in manifest.json for mismatches
  3. Do not prune config/layer files from a docker-save tar before importing
  4. Import via OCI layout (skopeo copy --format oci) if custom tooling broke the docker format
Defensive patterns

Strategy: validation

Validate before calling

mfsts, files := parseDockerSaveArchive("image.tar") // your own pre-check
for _, m := range mfsts {
    if !contains(files, m.Config) {
        return fmt.Errorf("archive inconsistent: config %s missing", m.Config)
    }
}

Try / catch

if err := client.Import(ctx, reader); err != nil {
    if strings.Contains(err.Error(), "image config") && strings.Contains(err.Error(), "not found") {
        // regenerate archive via docker save and retry
    }
    return err
}

Prevention

When it happens

Trigger: ImportIndex iterates manifest.json entries and blobs[mfst.Config] misses — the Config filename in manifest.json (e.g. "Config":"blobs/sha256/...") has no corresponding regular-file entry in the tar.

Common situations: manifest.json hand-edited or generated by custom tooling with wrong paths; archive where config files were deleted to save space; mixed archives combining files from different image exports; configs stored as symlinks whose targets are missing (related to error 271 resolution).

Related errors


AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02). Data as JSON: /api/errors/6c3d5afd629f7c5e. Report an issue: GitHub.