Your ARM image is listed under the wrong architecture, and docker manifest annotate is the fix you need before you push. This guide ends with a local manifest list whose platform metadata is explicit and checked. It takes about 15 minutes, and the examples use Docker CLI 29.8.1.
You need Docker CLI access, plus registry credentials if you intend to create or push a real list. The annotation edits only Docker's local manifest-list copy. It does not rebuild an image, change the image layers, or alter the Docker daemon.
Tip: This guide covers platform fields: operating system, architecture, OS version, OS features and architecture variant. It does not cover OCI key-value annotations, which are a different feature in newer build workflows.
Check the client version and the command's own option list:
$ docker version --format '{{.Client.Version}}'
29.8.1
$ docker manifest annotate --help
Usage: docker manifest annotate [OPTIONS] MANIFEST_LIST MANIFEST
Add additional information to a local image manifest
The installed manual marks this command as an addition to a local image manifest. Docker also labels the manifest command family experimental. Experimental behaviour can change between releases, so keep the client version in deployment notes when this command is part of a release process.
No root privilege is normally needed. The command talks to Docker's local manifest-list store, not to the engine, and it never modifies a running container. If your Docker installation uses a protected configuration directory, fix that access issue according to your local policy rather than adding sudo automatically.
annotate needs two positional arguments. The first is the name of the local manifest list. The second identifies one image manifest already included in that list. Create the list first when you do not already have one:
$ docker manifest create registry.example.invalid/acme/widget:2026.09 \
registry.example.invalid/acme/widget-amd64:2026.09 \
registry.example.invalid/acme/widget-arm64:2026.09
Replace every example registry name with your real registry and use image references that actually exist there. Docker queries the registry while creating the local list. A successful create leaves a local copy for inspection, annotation and a later push. It does not publish the list by itself.
If the list already exists locally, do not recreate it just to change one entry. Use docker manifest inspect first:
$ docker manifest inspect --verbose registry.example.invalid/acme/widget:2026.09
Look for the descriptor whose digest or image reference corresponds to the child you plan to annotate. The spelling and tag in the second positional argument must identify that child, not another list or an unrelated image.
Checkpoint: You have written down the manifest-list name, the child-manifest name and the intended platform. A typo fails clearly, but picking the wrong child produces a valid yet misleading list.
Suppose the ARM child was recorded without the architecture information you expect. Set the architecture with --arch:
$ docker manifest annotate \
registry.example.invalid/acme/widget:2026.09 \
registry.example.invalid/acme/widget-arm64:2026.09 \
--os linux \
--arch arm64
The installed manual does not describe any output for this command. A return to the shell counts as success only after you have checked the stored list in step 4. The annotation applies to the local copy named by the first argument; it does not change the child image in the registry.
Use the other options only when the child image really needs them:
--os sets the operating system, such as linux or windows.--arch sets the CPU architecture, such as amd64, arm or arm64.--variant sets an architecture variant, for example a variant required by an ARM image.--os-version records the operating-system version when the platform needs that distinction.--os-features records operating-system feature values. The installed option is a string list, so pass the option once for each value you need.Warning: Do not copy --variant from a different architecture, because a variant belongs to the architecture it describes. Do not invent an OS version or feature to fill a field either. Platform metadata influences which image a client selects, so inaccurate values can make a supported machine pull the wrong child.
Inspect the local list again, this time requesting verbose output:
$ docker manifest inspect --verbose \
registry.example.invalid/acme/widget:2026.09
Find the annotated child and check its platform object. For the command above, the relevant part should identify the child as Linux on ARM64:
{
"platform": {
"architecture": "arm64",
"os": "linux"
}
}
The complete output contains digests and other descriptor information, and its formatting can vary by client release. Check the values rather than comparing the entire output as text. If the child is absent, stop and correct the manifest-list or child reference. Do not push a list you have not matched to its intended image.
For an ARM variant, verify the additional field as well:
$ docker manifest annotate \
registry.example.invalid/acme/widget:2026.09 \
registry.example.invalid/acme/widget-arm:2026.09 \
--os linux --arch arm --variant v7
$ docker manifest inspect --verbose registry.example.invalid/acme/widget:2026.09
Tip: Only use v7 if the image was built for that ARM variant. The value is an example, not a safe default for every ARM image.
Once every child has the correct platform metadata, publish the local list:
$ docker manifest push registry.example.invalid/acme/widget:2026.09
This is the first command in the guide that publishes registry state. It normally requires registry authentication and permission to update the tag.
Warning: Do not use --insecure as a troubleshooting shortcut. The Docker documentation reserves that option for registries where ignoring normal certificate requirements is an explicit, understood decision. Prefer a correctly configured TLS certificate.
The push command can also remove the local list with --purge. That is optional and destructive to the local copy, so leave it off until the remote push has been checked. If you need to amend the list later, retaining the local copy is useful:
$ docker manifest inspect --verbose \
registry.example.invalid/acme/widget:2026.09
Recovery: To undo an annotation before pushing, annotate the same child again with the correct values and verify it. To recover after an incorrect list has already been pushed, correct the local copy, push the corrected list to the intended tag, and verify the remote result with an inspection command. Consider a new release tag when your release process does not permit replacing an existing tag.
annotate to edit.docker manifest create. The child may have been recorded by digest or under a different tag. Inspect the list and choose the descriptor you actually intend to change.--os-features and --os-version, not similarly named build or OCI annotation options.docker manifest inspect --verbose showed the expected OS, architecture and any required variant.