What went wrong?
When a service in a docker-compose.yaml consumed via WITH DOCKER --compose declares its image: with a digest pin, Earthbuild's compose-fetch step fails with refusing to create a tag with a digest reference and aborts the build.
The retag step uses the literal compose image: field as the docker tag target. The docker engine rejects any tag target containing @sha256: — so any digest-pinned reference, whether name:tag@sha256:… or name@sha256:…, breaks.
Minimal reproducer
Earthfile:
VERSION 0.8
repro:
FROM docker:29-dind
COPY docker-compose.yaml ./
WITH DOCKER --compose ./docker-compose.yaml
RUN docker compose ps
END
docker-compose.yaml:
services:
app:
image: alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
Run:
Observed output
+repro | Pulling 127.0.0.1:.../sess-…:img-0 and retagging as alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
+repro | refusing to create a tag with a digest reference
+repro | Downloading of images failed
+repro | error creating lease: Canceled: grpc: the client connection is closing: context canceled
+repro | ERROR Earthfile:6:3
+repro | The command
+repro | WITH DOCKER RUN ...
+repro | did not complete successfully. Exit code 1
Replacing the compose image: with alpine:3.20 (no digest) makes the build succeed.
The same error reproduces with a digest-only ref (image: alpine@sha256:d9e853…) — it's the @sha256: suffix on the retag target that the engine rejects, not the combination of tag + digest.
What should have happened?
Compose image: fields with digest pins are valid OCI references and are accepted by both Docker Engine and Compose v2 for docker pull / docker compose pull. Earthbuild's fetch-and-retag step should either:
- Detect digest-bearing refs and skip the retag (loading the image by content ID and letting compose resolve it by digest), or
- Retag under the tag-only form (
name:tag) and rely on compose's existing digest-verification semantics, or
- Document this as an explicit limitation and surface a clearer error message pointing users to the
WITH DOCKER --pull image@sha256:… workaround.
What earthly version?
earth --version
earth version vHEAD-8f019dd 8f019ddcc8464509fbefe55f36b5f9a599593094 darwin/arm64; macOS 26.4.1 homebrew-earthbuild
Buildkit Logs
No response
Other Helpful Information
Workaround
Wrap the digest-pinned reference in its own Earthfile target and load it via --load:
VERSION 0.8
alpine-pinned:
FROM alpine:3.20@sha256:d9e853e87e55526f6b2917df91a2115c36dd7c696a35be12163d44e6e2a4b6bc
SAVE IMAGE alpine:3.20
repro:
FROM docker:29-dind
COPY docker-compose.yaml ./
WITH DOCKER \
--compose ./docker-compose.yaml \
--load (+alpine-pinned)
RUN docker compose ps
END
services:
app:
image: alpine:3.20
This works because the digest is consumed by FROM (Earthbuild's own pull path, which handles digests correctly), SAVE IMAGE saves under a tag-only ref, and --load injects the image tarball into the dind daemon without invoking docker tag against a digest-bearing target.
It's also significantly more verbose than the natural image: …@sha256:… form, requires one extra target per pinned image, and makes the digest pin live in a different file from the service it pins — which is the heart of why this is worth fixing in Earthbuild rather than papering over.
Related
- Upstream tracking issue: earthly/earthly#1852 — sha-qualified images in
WITH DOCKER --pull are not available by that name. Covers the same class of bug from a different angle (--pull rather than compose) and remains open with no fix merged.
- Underlying engine restriction: docker/cli#4545 —
docker tag refusing digest-bearing targets is intentional behavior in the engine; the fix must live in Earthbuild's retag step.
What went wrong?
When a service in a
docker-compose.yamlconsumed viaWITH DOCKER --composedeclares itsimage:with a digest pin, Earthbuild's compose-fetch step fails withrefusing to create a tag with a digest referenceand aborts the build.The retag step uses the literal compose
image:field as thedocker tagtarget. The docker engine rejects any tag target containing@sha256:— so any digest-pinned reference, whethername:tag@sha256:…orname@sha256:…, breaks.Minimal reproducer
Earthfile:docker-compose.yaml:Run:
Observed output
Replacing the compose
image:withalpine:3.20(no digest) makes the build succeed.The same error reproduces with a digest-only ref (
image: alpine@sha256:d9e853…) — it's the@sha256:suffix on the retag target that the engine rejects, not the combination of tag + digest.What should have happened?
Compose
image:fields with digest pins are valid OCI references and are accepted by both Docker Engine and Compose v2 fordocker pull/docker compose pull. Earthbuild's fetch-and-retag step should either:name:tag) and rely on compose's existing digest-verification semantics, orWITH DOCKER --pull image@sha256:…workaround.What earthly version?
Buildkit Logs
No response
Other Helpful Information
Workaround
Wrap the digest-pinned reference in its own Earthfile target and load it via
--load:This works because the digest is consumed by
FROM(Earthbuild's own pull path, which handles digests correctly),SAVE IMAGEsaves under a tag-only ref, and--loadinjects the image tarball into the dind daemon without invokingdocker tagagainst a digest-bearing target.It's also significantly more verbose than the natural
image: …@sha256:…form, requires one extra target per pinned image, and makes the digest pin live in a different file from the service it pins — which is the heart of why this is worth fixing in Earthbuild rather than papering over.Related
WITH DOCKER --pullare not available by that name. Covers the same class of bug from a different angle (--pullrather than compose) and remains open with no fix merged.docker tagrefusing digest-bearing targets is intentional behavior in the engine; the fix must live in Earthbuild's retag step.