{"record":{"id":"f0cd7eb573263292","repo":"docker/compose","slug":"invalid-service-q-must-specify-either-image-or-b","errorCode":null,"errorMessage":"invalid service %q. Must specify either image or build","messagePattern":"invalid service %q\\. Must specify either image or build","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/api/api.go","lineNumber":236,"sourceCode":"\tPrint bool\n\t// Check let builder validate build configuration\n\tCheck bool\n\t// Attestations enables attestation generation\n\tAttestations bool\n\t// Provenance generate a provenance attestation\n\tProvenance string\n\t// SBOM generate a SBOM attestation\n\tSBOM string\n\t// Out is the stream to write build progress\n\tOut io.Writer\n}\n\n// Apply mutates project according to build options\nfunc (o BuildOptions) Apply(project *types.Project) error {\n\tplatform := project.Environment[\"DOCKER_DEFAULT_PLATFORM\"]\n\tfor name, service := range project.Services {\n\t\tif service.Provider == nil && service.Image == \"\" && service.Build == nil {\n\t\t\treturn fmt.Errorf(\"invalid service %q. Must specify either image or build\", name)\n\t\t}\n\n\t\tif service.Build == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif platform != \"\" {\n\t\t\tif len(service.Build.Platforms) > 0 && !slices.Contains(service.Build.Platforms, platform) {\n\t\t\t\treturn fmt.Errorf(\"service %q build.platforms does not support value set by DOCKER_DEFAULT_PLATFORM: %s\", name, platform)\n\t\t\t}\n\t\t\tservice.Platform = platform\n\t\t}\n\t\tif service.Platform != \"\" {\n\t\t\tif len(service.Build.Platforms) > 0 && !slices.Contains(service.Build.Platforms, service.Platform) {\n\t\t\t\treturn fmt.Errorf(\"service %q build configuration does not support platform: %s\", name, service.Platform)\n\t\t\t}\n\t\t}\n\n\t\tservice.Build.Pull = service.Build.Pull || o.Pull","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/pkg/api/api.go#L218-L254","documentation":"Thrown by api.BuildOptions.Apply while mutating the project before a build: every service in the compose model must be buildable or pullable, so it must declare an image, a build section, or come from a provider (service.Provider != nil). A service with none of these cannot be built or run, so the API rejects the whole project up front. The name in the message is the service key as written in compose.yaml.","triggerScenarios":"Calling api.BuildOptions.Apply(project) (directly or via the build/up API) on a project where a service defines neither image: nor build: and is not a provider-based service (e.g. a service containing only ports/env/depends_on). Also triggered by a typo'd key (e.g. images: or builds:) that compose-go silently ignores as an extension field.","commonSituations":"A compose.yaml service that was meant to be a config-only placeholder or was copy-pasted incompletely; indentation errors that push image:/build: under the wrong service or outside the service map; YAML typos that make the parser treat image as an unknown extension; using a service that only exists as a profile target with no runnable artifact.","solutions":["Open the compose file, find the named service, and add either an image: <tag> or a build: section (e.g. build: . with a Dockerfile)","If the service was meant to be provided externally, mark it with provider: so service.Provider is set and the check is skipped","Check YAML indentation around the service to confirm image:/build: are nested under the correct service key","Run docker compose config to let the CLI render the effective model and reveal services that lost their image/build keys"],"exampleFix":"# before (compose.yaml)\nservices:\n  web:\n    ports:\n      - \"8080:80\"\n# after\nservices:\n  web:\n    image: nginx:alpine\n    ports:\n      - \"8080:80\"\n","handlingStrategy":"validation","validationCode":"// Run before api.BuildOptions.Apply / compose build:\nfunc validateServices(project *types.Project) error {\n\tfor name, svc := range project.Services {\n\t\tif svc.Provider == nil && svc.Image == \"\" && svc.Build == nil {\n\t\t\treturn fmt.Errorf(\"service %q lacks image, build, and provider\", name)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat image-or-build as a required field in compose file linting (CI check on docker compose config)","Enable compose-go loader consistency validation so malformed services are rejected at load time","Use docker compose config in CI to catch schema drift before build"],"tags":["compose-api","validation","service-config","build"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}