{"record":{"id":"6dc766ab4fe89f98","repo":"docker/compose","slug":"your-compose-stack-cannot-be-published-as-it-only","errorCode":null,"errorMessage":"your Compose stack cannot be published as it only contains a build section for service(s):\n- %q\n","messagePattern":"your Compose stack cannot be published as it only contains a build section for service\\(s\\):\n- %q\n","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/compose/publish.go","lineNumber":666,"sourceCode":"\t\tlayers = append(layers, layerDescriptor)\n\t}\n\treturn layers\n}\n\nfunc (s *composeService) checkOnlyBuildSection(project *types.Project) (bool, error) {\n\terrorList := []string{}\n\tfor _, service := range project.Services {\n\t\tif service.Image == \"\" && service.Build != nil {\n\t\t\terrorList = append(errorList, service.Name)\n\t\t}\n\t}\n\tif len(errorList) > 0 {\n\t\tvar errMsg strings.Builder\n\t\terrMsg.WriteString(\"your Compose stack cannot be published as it only contains a build section for service(s):\\n\")\n\t\tfor _, serviceInError := range errorList {\n\t\t\tfmt.Fprintf(&errMsg, \"- %q\\n\", serviceInError)\n\t\t}\n\t\treturn false, errors.New(errMsg.String())\n\t}\n\treturn true, nil\n}\n\nfunc (s *composeService) checkForBindMount(project *types.Project) map[string][]types.ServiceVolumeConfig {\n\tallFindings := map[string][]types.ServiceVolumeConfig{}\n\tfor serviceName, config := range project.Services {\n\t\tbindMounts := []types.ServiceVolumeConfig{}\n\t\tfor _, volume := range config.Volumes {\n\t\t\tif volume.Type == types.VolumeTypeBind {\n\t\t\t\tbindMounts = append(bindMounts, volume)\n\t\t\t}\n\t\t}\n\t\tif len(bindMounts) > 0 {\n\t\t\tallFindings[serviceName] = bindMounts\n\t\t}\n\t}\n\treturn allFindings","sourceCodeStart":648,"sourceCodeEnd":684,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/compose/publish.go#L648-L684","documentation":"`docker compose publish` builds and pushes images to a registry; a service that has only `build:` and no `image:` produces an image with no registry tag to push, so the pre-flight check rejects the whole stack with a list of offending services. Every service must reference a publishable image name.","triggerScenarios":"Running `docker compose publish` when at least one service sets build: without an image: — canBePublished collects services where service.Image == \"\" && service.Build != nil and fails.","commonSituations":"Typical dev compose files build locally without tagging (`build: .` only); attempting to publish a dev-oriented stack; adding a new service and forgetting the image: tag.","solutions":["Add an `image: <registry>/<namespace>/<name>:<tag>` to every service that has `build:`","Use an override file (docker-compose.publish.yml) that adds image: entries, and publish with -f overrides","Remove non-publishable helper services from the published stack via profiles"],"exampleFix":"# before\nservices:\n  api:\n    build: .\n# after\nservices:\n  api:\n    build: .\n    image: ghcr.io/acme/api:latest","handlingStrategy":"validation","validationCode":"python3 - <<'EOF'\nimport yaml,sys\ncfg=yaml.safe_load(open('compose.yaml'))\nbad=[n for n,s in (cfg.get('services') or {}).items() if not s.get('image') and s.get('build')]\nif bad: sys.exit(f\"services missing image: {bad}\")\nprint('publishable')\nEOF","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Adopt the habit of always pairing build: with image: so every built service is tagged","Run the publishability check in CI before the actual publish job"],"tags":["publish","registry","compose-file","validation"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}