docker/cli · error
invalid image reference for service
Error message
invalid image reference for service %s: no image specified
What it means
Raised by loadComposeFile when a service has no image defined (svc.Image == ""). Swarm services require an image reference because they cannot build; the error fires at loader.go:57 before the spec is ever sent to the daemon.
Solutions
- Add an `image:` to the service in compose.yml (preferably the same tag you build and push).
- Build and push the image in CI, then reference the pushed tag in `image:`.
- If using multi-stage, ensure the final image reference is set.
- Validate with `docker compose config` to confirm image is populated.
Example fix
# before
services:
web:
build: .
# after
services:
web:
image: myregistry/web:1.0.0
build: . Defensive patterns
Strategy: validation
Validate before calling
// Ensure every service has an image before stack deploy
for _, svc := range config.Services {
if svc.Image == "" {
return fmt.Errorf("service %q needs an image for swarm deploy", svc.Name)
}
} Type guard
type DeployableService struct {
Name string
Image string // required, non-empty
}
func isDeployable(s composetypes.ServiceConfig) bool {
return strings.TrimSpace(s.Image) != ""
} Prevention
- Always pair `build:` with `image:` when targeting Swarm.
- In CI, build-push then inject the tag into compose before deploy.
- Lint compose files for missing image fields.
When it happens
Trigger: A compose service using only `build:` without `image:`, deployed via `docker stack deploy`. Swarm cannot build images, so each service must declare an image. The loop at loader.go:55 checks every service's Image field.
Common situations: Using a compose file built for `docker compose up` (where build-only is fine) and pointing `docker stack deploy` at it; forgetting to add image: after adding build:; CI that builds and pushes images but the compose file wasn't updated to reference them.
Related errors
- invalid image reference for service
- specify a Compose file (with --compose-file)
- compose file contains unsupported options
- unexpected environment variable
- invalid stack name
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/90fc68f5bf2d7f09.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/stack/loader.go:57
}
dicts := getDictsFrom(configDetails.ConfigFiles)
unsupportedProperties := loader.GetUnsupportedProperties(dicts...)
if len(unsupportedProperties) > 0 {
_, _ = fmt.Fprintf(streams.Err(), "Ignoring unsupported options: %s\n\n",
strings.Join(unsupportedProperties, ", "))
}
deprecatedProperties := loader.GetDeprecatedProperties(dicts...)
if len(deprecatedProperties) > 0 {
_, _ = fmt.Fprintf(streams.Err(), "Ignoring deprecated options:\n\n%s\n\n",
propertyWarnings(deprecatedProperties))
}
// Validate if each service has a valid image-reference.
for _, svc := range config.Services {
if svc.Image == "" {
return nil, fmt.Errorf("invalid image reference for service %s: no image specified", svc.Name)
}
if _, err := reference.ParseAnyReference(svc.Image); err != nil {
return nil, fmt.Errorf("invalid image reference for service %s: %w", svc.Name, err)
}
}
return config, nil
}
func getDictsFrom(configFiles []composetypes.ConfigFile) []map[string]any {
dicts := make([]map[string]any, 0, len(configFiles))
for _, configFile := range configFiles {
dicts = append(dicts, configFile.Config)
}
return dicts
}
View on GitHub (pinned to 4f84911bfe)