{"record":{"id":"90fc68f5bf2d7f09","repo":"docker/cli","slug":"invalid-image-reference-for-service-s-no-image-s","errorCode":null,"errorMessage":"invalid image reference for service %s: no image specified","messagePattern":"invalid image reference for service (.+?): no image specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/stack/loader.go","lineNumber":57,"sourceCode":"\t}\n\n\tdicts := getDictsFrom(configDetails.ConfigFiles)\n\tunsupportedProperties := loader.GetUnsupportedProperties(dicts...)\n\tif len(unsupportedProperties) > 0 {\n\t\t_, _ = fmt.Fprintf(streams.Err(), \"Ignoring unsupported options: %s\\n\\n\",\n\t\t\tstrings.Join(unsupportedProperties, \", \"))\n\t}\n\n\tdeprecatedProperties := loader.GetDeprecatedProperties(dicts...)\n\tif len(deprecatedProperties) > 0 {\n\t\t_, _ = fmt.Fprintf(streams.Err(), \"Ignoring deprecated options:\\n\\n%s\\n\\n\",\n\t\t\tpropertyWarnings(deprecatedProperties))\n\t}\n\n\t// Validate if each service has a valid image-reference.\n\tfor _, svc := range config.Services {\n\t\tif svc.Image == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"invalid image reference for service %s: no image specified\", svc.Name)\n\t\t}\n\t\tif _, err := reference.ParseAnyReference(svc.Image); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"invalid image reference for service %s: %w\", svc.Name, err)\n\t\t}\n\t}\n\n\treturn config, nil\n}\n\nfunc getDictsFrom(configFiles []composetypes.ConfigFile) []map[string]any {\n\tdicts := make([]map[string]any, 0, len(configFiles))\n\tfor _, configFile := range configFiles {\n\t\tdicts = append(dicts, configFile.Config)\n\t}\n\n\treturn dicts\n}\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/stack/loader.go#L39-L75","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before\nservices:\n  web:\n    build: .\n# after\nservices:\n  web:\n    image: myregistry/web:1.0.0\n    build: .","handlingStrategy":"validation","validationCode":"// Ensure every service has an image before stack deploy\nfor _, svc := range config.Services {\n    if svc.Image == \"\" {\n        return fmt.Errorf(\"service %q needs an image for swarm deploy\", svc.Name)\n    }\n}","typeGuard":"type DeployableService struct {\n    Name  string\n    Image string // required, non-empty\n}\n\nfunc isDeployable(s composetypes.ServiceConfig) bool {\n    return strings.TrimSpace(s.Image) != \"\"\n}","tryCatchPattern":null,"preventionTips":["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."],"tags":["docker","stack","compose","image","build","validation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}