{"record":{"id":"6c3d5afd629f7c5e","repo":"containerd/containerd","slug":"image-config-q-not-found","errorCode":null,"errorMessage":"image config %q not found","messagePattern":"image config %q not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/images/archive/importer.go","lineNumber":166,"sourceCode":"\t}\n\n\tfor name, linkname := range symlinks {\n\t\tdesc, ok := blobs[linkname]\n\t\tif !ok {\n\t\t\treturn ocispec.Descriptor{}, fmt.Errorf(\"no target for symlink layer from %q to %q\", name, linkname)\n\t\t}\n\t\tblobs[name] = desc\n\t}\n\n\tidx := ocispec.Index{\n\t\tVersioned: specs.Versioned{\n\t\t\tSchemaVersion: 2,\n\t\t},\n\t}\n\tfor _, mfst := range mfsts {\n\t\tconfig, ok := blobs[mfst.Config]\n\t\tif !ok {\n\t\t\treturn ocispec.Descriptor{}, fmt.Errorf(\"image config %q not found\", mfst.Config)\n\t\t}\n\t\tconfig.MediaType = images.MediaTypeDockerSchema2Config\n\n\t\tlayers, err := resolveLayers(ctx, store, mfst.Layers, blobs, iopts.compress)\n\t\tif err != nil {\n\t\t\treturn ocispec.Descriptor{}, fmt.Errorf(\"failed to resolve layers: %w\", err)\n\t\t}\n\n\t\tmanifest := struct {\n\t\t\tSchemaVersion int                  `json:\"schemaVersion\"`\n\t\t\tMediaType     string               `json:\"mediaType\"`\n\t\t\tConfig        ocispec.Descriptor   `json:\"config\"`\n\t\t\tLayers        []ocispec.Descriptor `json:\"layers\"`\n\t\t}{\n\t\t\tSchemaVersion: 2,\n\t\t\tMediaType:     images.MediaTypeDockerSchema2Manifest,\n\t\t\tConfig:        config,\n\t\t\tLayers:        layers,","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/core/images/archive/importer.go#L148-L184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","solutions":["Re-run `docker save -o image.tar <image>` to regenerate a self-consistent archive","Cross-check `tar tf image.tar` against the Config paths in manifest.json for mismatches","Do not prune config/layer files from a docker-save tar before importing","Import via OCI layout (skopeo copy --format oci) if custom tooling broke the docker format"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"mfsts, files := parseDockerSaveArchive(\"image.tar\") // your own pre-check\nfor _, m := range mfsts {\n    if !contains(files, m.Config) {\n        return fmt.Errorf(\"archive inconsistent: config %s missing\", m.Config)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := client.Import(ctx, reader); err != nil {\n    if strings.Contains(err.Error(), \"image config\") && strings.Contains(err.Error(), \"not found\") {\n        // regenerate archive via docker save and retry\n    }\n    return err\n}","preventionTips":["Never hand-edit manifest.json config paths","Regenerate archives with docker save instead of repacking by hand","Cross-check manifest.json entries against tar contents in CI before import","Avoid pruning config files from docker-save archives"],"tags":["docker-archive","manifest","image-import"],"backgroundTag":"manifest-references-missing-blob","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}