containerd/containerd · error
media-type: expected manifest but found index (%s)
Error message
media-type: expected manifest but found index (%s)
What it means
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.
Source
Thrown at core/images/image.go:402
Layers json.RawMessage `json:"layers,omitempty"`
Manifests json.RawMessage `json:"manifests,omitempty"`
FSLayers json.RawMessage `json:"fsLayers,omitempty"` // schema 1
}
// validateMediaType returns an error if the byte slice is invalid JSON,
// if the format of the blob is not supported, or if the media type
// identifies the blob as one format, but it identifies itself as, or
// contains elements of another format.
func validateMediaType(b []byte, mt string) error {
var doc unknownDocument
if err := json.Unmarshal(b, &doc); err != nil {
return err
}
if len(doc.FSLayers) != 0 {
return fmt.Errorf("media-type: schema 1 not supported")
}
if IsManifestType(mt) && (len(doc.Manifests) != 0 || IsIndexType(doc.MediaType)) {
return fmt.Errorf("media-type: expected manifest but found index (%s)", mt)
} else if IsIndexType(mt) && (len(doc.Config) != 0 || len(doc.Layers) != 0 || IsManifestType(doc.MediaType)) {
return fmt.Errorf("media-type: expected index but found manifest (%s)", mt)
}
return nil
}
// RootFS returns the unpacked diffids that make up and images rootfs.
//
// These are used to verify that a set of layers unpacked to the expected
// values.
func RootFS(ctx context.Context, provider content.Provider, configDesc ocispec.Descriptor) ([]digest.Digest, error) {
p, err := content.ReadBlob(ctx, provider, configDesc)
if err != nil {
return nil, err
}
var config ocispec.Image
if err := json.Unmarshal(p, &config); err != nil {View on GitHub (pinned to 4246446a2b)
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).
Example fix
// before: mislabeled descriptor
desc := ocispec.Descriptor{MediaType: ocispec.MediaTypeImageManifest, Digest: idxDigest}
// after
desc := ocispec.Descriptor{MediaType: ocispec.MediaTypeImageIndex, Digest: idxDigest} Defensive patterns
Strategy: validation
Validate before calling
var probe struct{ Manifests json.RawMessage `json:"manifests"` }
// before treating desc as a manifest: ensure no manifests array present Type guard
func looksLikeManifest(blob []byte) bool {
var d struct{ Manifests json.RawMessage `json:"manifests"`; MediaType string `json:"mediaType"` }
json.Unmarshal(blob, &d)
return len(d.Manifests) == 0 && !images.IsIndexType(d.MediaType)
} Try / catch
children, err := images.Children(ctx, store, desc)
if err != nil && strings.Contains(err.Error(), "expected manifest but found index") {
return fixDescriptorMediaType(desc, ocispec.MediaTypeImageIndex)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- media-type: expected index but found manifest (%s)
- manifest: invalid desc %s: %w
- NotFound
- children: invalid desc %s: %w
- no processor for media-type
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/c34ee67c9c6942f6.
Report an issue: GitHub.