docker/cli · error

manifest must have an OS and Architecture to be pushed to a…

Error message

manifest %s must have an OS and Architecture to be pushed to a registry

What it means

Returned by `buildManifestList` (push.go:127-132) when a constituent manifest has `Descriptor.Platform == nil` or an empty OS/Architecture. A registry requires every manifest-list entry to declare a platform, so the push is aborted before any network call. This happens when an image was added without annotation and its source manifest lacked platform metadata.

Solutions

  1. Annotate each offending entry: `docker manifest annotate --os linux --arch amd64 list img`.
  2. Re-create the list using images that carry platform metadata.
  3. Inspect each member to find which one is missing platform info.
  4. Push each single-arch image separately if a manifest list is not required.

Example fix

# before
docker manifest create mylist img-no-platform
docker manifest push mylist        # fails
# after
docker manifest annotate mylist img-no-platform --os linux --arch amd64
docker manifest push mylist
Defensive patterns

Strategy: validation

Validate before calling

// verify every member has platform metadata before pushing
for _, m := range manifests {
    if m.Descriptor.Platform == nil ||
        m.Descriptor.Platform.OS == "" ||
        m.Descriptor.Platform.Architecture == "" {
        return fmt.Errorf("member %s missing OS/Architecture; annotate before push", m.Ref)
    }
}

Type guard

func hasPlatform(m types.ImageManifest) bool {
    p := m.Descriptor.Platform
    return p != nil && p.OS != "" && p.Architecture != ""
}

Try / catch

if err := runPush(ctx, cli, opts); err != nil {
    if strings.Contains(err.Error(), "must have an OS and Architecture") {
        // identify and annotate the offending member
        return annotateMissingPlatforms(manifests)
    }
    return err
}

Prevention

When it happens

Trigger: Running `docker manifest create list img` where `img` is a single-arch image whose manifest has no platform, then `docker manifest push list` without annotating --os/--arch.

Common situations: Forgetting `docker manifest annotate --os --arch` after create, or adding an image from a registry that omits platform fields.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/d3d4fb247f027d47. Report an issue: GitHub.

Appendix: source

Thrown at cli/command/manifest/push.go:131

			manifestPush, err := buildPutManifestRequest(imageManifest, targetRef)
			if err != nil {
				return req, err
			}
			req.mountRequests = append(req.mountRequests, manifestPush)
		}
	}
	return req, nil
}

func buildManifestList(manifests []types.ImageManifest, targetRef reference.Named) (*manifestlist.DeserializedManifestList, error) {
	targetRepo := reference.TrimNamed(targetRef)
	descriptors := make([]manifestlist.ManifestDescriptor, 0, len(manifests))
	for _, imageManifest := range manifests {
		if imageManifest.Descriptor.Platform == nil ||
			imageManifest.Descriptor.Platform.Architecture == "" ||
			imageManifest.Descriptor.Platform.OS == "" {
			return nil, fmt.Errorf("manifest %s must have an OS and Architecture to be pushed to a registry", imageManifest.Ref)
		}
		descriptor, err := buildManifestDescriptor(targetRepo, imageManifest)
		if err != nil {
			return nil, err
		}
		descriptors = append(descriptors, descriptor)
	}

	return manifestlist.FromDescriptors(descriptors)
}

func buildManifestDescriptor(targetRepo reference.Named, imageManifest types.ImageManifest) (manifestlist.ManifestDescriptor, error) {
	manifestRepoHostname := reference.Domain(reference.TrimNamed(imageManifest.Ref))
	targetRepoHostname := reference.Domain(reference.TrimNamed(targetRepo))
	if manifestRepoHostname != targetRepoHostname {
		return manifestlist.ManifestDescriptor{}, fmt.Errorf("cannot use source images from a different registry than the target image: %s != %s", manifestRepoHostname, targetRepoHostname)
	}

View on GitHub (pinned to 4f84911bfe)