fly machine run duplicates sha256 digest when image ref is digest-form, rejects as invalid image identifier

Running fly machine run with an image reference in digest form

...@sha256:<hash>

causes flyctl to append the digest to the ref a second time when constructing the Machine config. The resulting @sha256:X@sha256:X ref is then rejected by the Machines API.

Minimal reproduction

Using a public image so anyone can run this:

$ fly apps create repro-digest-bug --org personalNew app created: repro-digest-bug

$ fly machine run  "docker.io/library/alpine@sha256:b58899f069c47216f6002a6850143dc6fae0d35eb8b0df9300bbe6327b9c2171" –region iad–app repro-digest-bug

Searching for image…
  'docker.io/library/alpine@sha256:b58899f069c47216f6002a6850143dc6fae0d35eb8b0df9300bbe6327b9c2171' remotely...
  image found: img_ox20prjmdjm2vj1z
  Image: docker-hub-mirror.fly.io/library/alpine@sha256:b58899f069c47216f6002a6850143dc6fae0d35eb8b0df9300bbe6327b9c217
  1@sha256:b58899f069c47216f6002a6850143dc6fae0d35eb8b0df9300bbe6327b9c2171
  Image size: 3.4 MB


Error: could not launch machine: failed to launch VM: config.image: invalid image identifier

Note the Image: line — the digest has been appended twice. The initial Searching for image ‘…’ line shows the ref correctly, so the doubling happens after image resolution, during machine config construction.

The Machines API supports digest-form refs in config.image — fly machine clone produces image refs like registry-1.docker.io/my-app/sleep:latest@sha256:597c3e, and running
machines expose an image_ref with a populated digest field. So fly machine seems like it should accept the same form without mangling it.

Using a tag instead works fine:
$ fly machine run "docker.io/library/alpine:3.19" --region iad --app repro-digest-bug

The bug is independent of:

  • Region — reproduces in both fra1 and iad.
  • Org — reproduces in two different orgs I have access to.
  • Registry — reproduces with both registry.fly.io/<org>/<image>@sha256:... (Fly per-org registry) and docker.io/library/<image>@sha256:... (rewritten by Fly to
      docker-hub-mirror.fly.io)
    

fly v0.4.36 darwin/arm64, Commit: c8dc0095, BuildDate: 2026-04-16

Wondering if this is expected behavior, but it would be nice to use immutable references here!

(Edits for formatting / missing info)

that does seem like a bug!

Aha, I was assuming that the digest was sufficient to identify the image given the repo.

repo:tag@sha256:<digest> works fine, so keeping the tag and appending the digest should work. Hopefully helpful for someone who misses this detail in the future!