{"record":{"id":"c34ee67c9c6942f6","repo":"containerd/containerd","slug":"media-type-expected-manifest-but-found-index-s","errorCode":null,"errorMessage":"media-type: expected manifest but found index (%s)","messagePattern":"media-type: expected manifest but found index \\((.+?)\\)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/images/image.go","lineNumber":402,"sourceCode":"\tLayers    json.RawMessage `json:\"layers,omitempty\"`\n\tManifests json.RawMessage `json:\"manifests,omitempty\"`\n\tFSLayers  json.RawMessage `json:\"fsLayers,omitempty\"` // schema 1\n}\n\n// validateMediaType returns an error if the byte slice is invalid JSON,\n// if the format of the blob is not supported, or if the media type\n// identifies the blob as one format, but it identifies itself as, or\n// contains elements of another format.\nfunc validateMediaType(b []byte, mt string) error {\n\tvar doc unknownDocument\n\tif err := json.Unmarshal(b, &doc); err != nil {\n\t\treturn err\n\t}\n\tif len(doc.FSLayers) != 0 {\n\t\treturn fmt.Errorf(\"media-type: schema 1 not supported\")\n\t}\n\tif IsManifestType(mt) && (len(doc.Manifests) != 0 || IsIndexType(doc.MediaType)) {\n\t\treturn fmt.Errorf(\"media-type: expected manifest but found index (%s)\", mt)\n\t} else if IsIndexType(mt) && (len(doc.Config) != 0 || len(doc.Layers) != 0 || IsManifestType(doc.MediaType)) {\n\t\treturn fmt.Errorf(\"media-type: expected index but found manifest (%s)\", mt)\n\t}\n\treturn nil\n}\n\n// RootFS returns the unpacked diffids that make up and images rootfs.\n//\n// These are used to verify that a set of layers unpacked to the expected\n// values.\nfunc RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {\n\tp, err := content.ReadBlob(ctx, provider, configDesc)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tvar config ocispec.Image\n\tif err := json.Unmarshal(p, &config); err != nil {","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/core/images/image.go#L384-L420","documentation":"validateMediaType returns \"media-type: expected manifest but found index\" when a blob whose descriptor says it is a manifest actually contains a manifests array or self-identifies as an index. This is a descriptor/blob mediaType contradiction caught during Children() traversal.","triggerScenarios":"images.Children() on a descriptor whose MediaType is a manifest type (docker schema2 manifest or OCI manifest) but whose JSON body has a non-empty \"manifests\" field or internal mediaType of an index.","commonSituations":"Custom push code labeling a multi-arch index as a single-platform manifest; registries/mirrors serving the wrong blob for a digest; hand-crafted OCI layouts with copy-paste mediaType mistakes.","solutions":["Fix the mediaType on the descriptor to the index type (application/vnd.oci.image.index.v1+json or docker manifest list) when pushing multi-arch content.","Verify the registry is returning the blob matching the requested digest (curl + jq the blob).","Re-generate the image layout with an OCI-compliant tool (buildkit, oras, skopeo)."],"exampleFix":"// before: mislabeled descriptor\ndesc := ocispec.Descriptor{MediaType: ocispec.MediaTypeImageManifest, Digest: idxDigest}\n// after\ndesc := ocispec.Descriptor{MediaType: ocispec.MediaTypeImageIndex, Digest: idxDigest}","handlingStrategy":"validation","validationCode":"var probe struct{ Manifests json.RawMessage `json:\"manifests\"` }\n// before treating desc as a manifest: ensure no manifests array present","typeGuard":"func looksLikeManifest(blob []byte) bool {\n\tvar d struct{ Manifests json.RawMessage `json:\"manifests\"`; MediaType string `json:\"mediaType\"` }\n\tjson.Unmarshal(blob, &d)\n\treturn len(d.Manifests) == 0 && !images.IsIndexType(d.MediaType)\n}","tryCatchPattern":"children, err := images.Children(ctx, store, desc)\nif err != nil && strings.Contains(err.Error(), \"expected manifest but found index\") {\n\treturn fixDescriptorMediaType(desc, ocispec.MediaTypeImageIndex)\n}","preventionTips":["Use ocispec constants instead of hand-written mediaType strings in push code.","For multi-arch pushes, create a real index rather than reusing a manifest descriptor.","Validate pushed blobs by fetching them back and comparing internal vs declared media types."],"tags":["manifest","index","media-type"],"backgroundTag":"media-type-mismatch","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}