docker/compose · error

invalid service %q. Must specify either image or build

Error message

invalid service %q. Must specify either image or build

What it means

Same contract as error 120 but enforced later, in composeService.ensureImagesExists (build/up pipeline): before pulling or building, compose verifies each service declares image, build, or provider. This is the runtime backstop for projects that reach the build phase without passing the earlier api.BuildOptions.Apply validation (e.g. paths that skip Apply).

Source

Thrown at pkg/compose/build.go:112

	if len(serviceToBuild) == 0 {
		return imageIDs, nil
	}

	bake, err := buildWithBake(s.dockerCli)
	if err != nil {
		return nil, err
	}
	if bake {
		return s.doBuildBake(ctx, project, serviceToBuild, options)
	}
	return s.doBuildClassic(ctx, project, serviceToBuild, options)
}

func (s *composeService) ensureImagesExists(ctx context.Context, project *types.Project, buildOpts *api.BuildOptions, quietPull bool) error {
	for name, service := range project.Services {
		if service.Provider == nil && service.Image == "" && service.Build == nil {
			return fmt.Errorf("invalid service %q. Must specify either image or build", name)
		}
	}

	images, pinnedDigests, err := s.getLocalImagesDigests(ctx, project)
	if err != nil {
		return err
	}

	err = tracing.SpanWrapFunc("project/pull", tracing.ProjectOptions(ctx, project),
		func(ctx context.Context) error {
			return s.pullRequiredImages(ctx, project, images, quietPull)
		},
	)(ctx)
	if err != nil {
		return err
	}

	if buildOpts != nil {

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. Add image: or build: to the named service in compose.yaml
  2. If the service is external, give it a provider: block
  3. Load projects with validation enabled (compose-go loader with consistency checks) so the mistake is caught earlier with a clearer message
  4. Run docker compose config to inspect the effective service definition

Example fix

# before
services:
  worker:
    command: ["python", "worker.py"]
# after
services:
  worker:
    build: ./worker
    command: ["python", "worker.py"]
Defensive patterns

Strategy: validation

Validate before calling

// Before compose build/up on a programmatically loaded project:
for name, svc := range project.Services {
	if svc.Provider == nil && svc.Image == "" && svc.Build == nil {
		return fmt.Errorf("service %q cannot be built or pulled: add image/build/provider", name)
	}
}

Prevention

When it happens

Trigger: Calling the build or up API on a project whose service has no image/build/provider — commonly when the project was loaded with loaders that skip validation (WithConsistency off) or constructed programmatically and passed straight to compose.Service.Build/Up.

Common situations: Programmatic users of pkg/compose building a *types.Project by hand; YAML typos (images:) that remove the image key; services intended only as metadata that accidentally stay enabled because their profile is active.

Related errors


AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15). Data as JSON: /api/errors/9d4d2f590ad45404. Report an issue: GitHub.