docker/compose · error

the classic builder doesn't support SSH keys, set DOCKER_BUI

Error message

the classic builder doesn't support SSH keys, set DOCKER_BUILDKIT=1 to use BuildKit

What it means

Returned by doBuildClassic when a service's build section declares SSH keys (`build.ssh`) but the legacy classic builder is in use. The classic builder has no mechanism to forward SSH agent keys into the build, so Compose aborts before invoking the builder. BuildKit is required because only it implements `#syntax` SSH mount forwarding.

Source

Thrown at pkg/compose/build_classic.go:143

func (s *composeService) doBuildImage(ctx context.Context, project *types.Project, service types.ServiceConfig, options api.BuildOptions) (string, error) {
	var (
		buildCtx      io.ReadCloser
		dockerfileCtx io.ReadCloser
		contextDir    string
		relDockerfile string
	)

	if len(service.Build.Platforms) > 1 {
		return "", fmt.Errorf("the classic builder doesn't support multi-arch build, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if service.Build.Privileged {
		return "", fmt.Errorf("the classic builder doesn't support privileged mode, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if len(service.Build.AdditionalContexts) > 0 {
		return "", fmt.Errorf("the classic builder doesn't support additional contexts, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if len(service.Build.SSH) > 0 {
		return "", fmt.Errorf("the classic builder doesn't support SSH keys, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if len(service.Build.Secrets) > 0 {
		return "", fmt.Errorf("the classic builder doesn't support secrets, set DOCKER_BUILDKIT=1 to use BuildKit")
	}

	if service.Build.Labels == nil {
		service.Build.Labels = make(map[string]string)
	}
	service.Build.Labels[api.ImageBuilderLabel] = "classic"

	dockerfileName := dockerFilePath(service.Build.Context, service.Build.Dockerfile)
	specifiedContext := service.Build.Context
	progBuff := s.stdout()
	buildBuff := s.stdout()

	contextType, err := build.DetectContextType(specifiedContext)
	if err != nil {
		return "", err

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. Set DOCKER_BUILDKIT=1 in the environment (or remove DOCKER_BUILDKIT=0) and re-run the build
  2. Alternatively set COMPOSE_BAKE=true or ensure the Docker CLI >= 18.09 and daemon >= 18.09 so BuildKit is the default
  3. If the classic builder is mandatory, remove the `ssh:` block from the service's build section and use a non-SSH strategy (e.g. build args with a deploy key, or a multistage fetch outside the build)

Example fix

# docker-compose.yml (before)
services:
  app:
    build:
      context: .
      ssh:
        - default  # fails with classic builder

# after: enable BuildKit
# export DOCKER_BUILDKIT=1
docker compose build
Defensive patterns

Strategy: validation

Validate before calling

// before building, reject classic builder if build.ssh is used
if len(svc.Build.SSH) > 0 {
    bk, err := dockerCli.BuildKitEnabled()
    if err != nil {
        return err
    }
    if !bk {
        return fmt.Errorf("service %s needs DOCKER_BUILDKIT=1 for build.ssh", svc.Name)
    }
}

Prevention

When it happens

Trigger: Running `docker compose build` (or `up --build`) on a service with `build.ssh` configured while the code path resolves to doBuildClassic — i.e. DOCKER_BUILDKIT=0 is set, or the docker CLI/daemon is old enough that BuildKit is not the default, and COMPOSE_BAKE/BUILDKIT escalation is disabled.

Common situations: CI pipelines pinning DOCKER_BUILDKIT=0 for reproducibility; corporate baselines with old dockerd versions; composing files that added `ssh:` to fetch private repos during RUN git clone; DOCKER_BUILDKIT explicitly disabled to get classic builder logs.

Related errors


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