Skip to content

fix: type=image volume source is always a docker image reference - #929

Merged
glours merged 1 commit into
compose-spec:mainfrom
ndeloof:remove-image-volume-service-ref
Sep 16, 2026
Merged

glours merged 1 commit into
compose-spec:mainfrom
ndeloof:remove-image-volume-service-ref

Conversation

@ndeloof

@ndeloof ndeloof commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

This PR removes an undocumented, unintended behavior: a type: image volume's source silently stops being resolved as an image whenever it happens to match the name of another service in the project.

Context

05-services.md documents source for a type: image mount as "a docker image reference" — nothing else. But WithImagesResolved currently special-cases it: if source matches an active or profile-disabled service name, digest resolution is skipped entirely and the raw name is passed through untouched, as if it were an implicit reference to that other service's locally built image.

This special-casing was never proposed or reviewed as a feature. It landed as a side effect of #894/#899 (wiring up dependent-image resolution for WithImagesResolved), is absent from the spec text and JSON schema, and has no integration anywhere else in the dependency graph: DependsOn, service selection (WithSelectedServices) and build ordering all remain unaware of it. In practice this means the "referenced" service isn't reliably built/pulled before the mount is used, so the only working case today is coincidental (the target image already exists locally under that name).

What this PR brings

type: image volume sources are now always resolved as plain docker image references, consistently with the documented spec and with how the service's own image: and pre_start hook images are already handled. A source that isn't a syntactically valid docker reference (e.g. one that happens to reuse a mixed-case service name) now fails resolution with a clear error instead of being silently passed through.

If mounting another service's build output is wanted as an actual feature, it deserves an explicit, documented reference form — e.g. source: service:xxx — consistent with how the spec already expresses inter-service references elsewhere (build.additional_contexts: [service:xxx]), rather than an implicit fallback triggered by a name collision.

Found while reviewing docker/compose#13811.

🤖 Generated with Claude Code

WithImagesResolved silently skipped digest resolution whenever a
type=image volume source happened to match the name of another
service in the project (active or profile-disabled), treating it as
an implicit reference to that service's locally built image.

This was never part of the Compose Spec: source for a type=image
mount is documented (05-services.md) as "a docker image reference",
nothing else. The behavior was an incorrectly implemented side effect
introduced in compose-spec#894/compose-spec#899 while wiring up digest resolution for
dependent images, never reviewed as a feature in its own right, and
never reflected in the spec or schema. It also has no integration
with the rest of the dependency machinery (DependsOn, service
selection, build ordering): the referenced service is not treated as
a dependency anywhere else, so relying on this silently produced
broken results outside of narrow, coincidental setups.

Remove the special-casing: a type=image source is now always resolved
as a plain image reference, like any other. An invalid one (e.g. one
that happens to reuse a mixed-case service name) now fails resolution
instead of being silently passed through.

If a mount sourced from another service's build output is wanted as a
real feature, it should be a new, explicit reference form (e.g.
`source: service:xxx`), consistent with how other inter-service
references are expressed in the Compose Spec (e.g.
`additional_contexts: [service:xxx]`) — not an implicit fallback on
name collision.

Found while reviewing docker/compose#13811.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>

@glours glours left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@glours
glours merged commit 9047519 into compose-spec:main Sep 16, 2026
8 checks passed
ndeloof added a commit to ndeloof/compose that referenced this pull request Sep 21, 2026
compose-go's WithImagesResolved no longer special-cases a type=image
volume source that happens to match another service's name -- per
compose-spec/compose-go#929, such a source is always resolved as a
plain docker image reference, never treated as an implicit reference
to that service's locally built image. This surfaced as a real CI
failure after bumping the compose-go pin: the mock in
TestResolveImageDigests only expected calls for nginx/someimage/
hookimage and panicked on the now-unexpected lookup for "builder".

Update the test to expect the volume source to resolve like any other
image reference, and drop the stale comment in resolveServiceImageDigests
describing the old, now-removed behavior.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
glours pushed a commit to docker/compose that referenced this pull request Sep 21, 2026
compose-go's WithImagesResolved no longer special-cases a type=image
volume source that happens to match another service's name -- per
compose-spec/compose-go#929, such a source is always resolved as a
plain docker image reference, never treated as an implicit reference
to that service's locally built image. This surfaced as a real CI
failure after bumping the compose-go pin: the mock in
TestResolveImageDigests only expected calls for nginx/someimage/
hookimage and panicked on the now-unexpected lookup for "builder".

Update the test to expect the volume source to resolve like any other
image reference, and drop the stale comment in resolveServiceImageDigests
describing the old, now-removed behavior.

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants