docker/compose · error

volume with type=image require Docker Engine %s or later

Error message

volume with type=image require Docker Engine %s or later

What it means

Thrown when a service volume uses the newer 'type: image' mount (mount an image as a volume) but the connected Docker Engine negotiates an API version below 1.48 (Docker Engine < v28). The daemon validates image mounts against the API version negotiated from the request path, so compose pre-checks s.RuntimeAPIVersion(ctx) and refuses early with a clear message instead of an opaque daemon error.

Source

Thrown at pkg/compose/create.go:986

		case mount.TypeVolume:
			v := findVolumeByTarget(service.Volumes, m.Target)
			vol := findVolumeByName(p.Volumes, m.Source)
			if v != nil && vol != nil {
				// Prefer the bind API if no advanced option is used, to preserve backward compatibility
				if !volumeRequiresMountAPI(v.Volume) {
					binds = append(binds, toBindString(vol.Name, v))
					continue
				}
			}
		case mount.TypeImage:
			// The daemon validates image mounts against the negotiated API version
			// from the request path, not the server's own max version.
			version, err := s.RuntimeAPIVersion(ctx)
			if err != nil {
				return nil, nil, err
			}
			if versions.LessThan(version, apiVersion148) {
				return nil, nil, fmt.Errorf("volume with type=image require Docker Engine %s or later", dockerEngineV28)
			}
		}
		mounts = append(mounts, m)
	}
	return binds, mounts, nil
}

func toBindString(name string, v *types.ServiceVolumeConfig) string {
	access := "rw"
	if v.ReadOnly {
		access = "ro"
	}
	options := []string{access}
	if v.Bind != nil && v.Bind.SELinux != "" {
		options = append(options, v.Bind.SELinux)
	}
	if v.Bind != nil && v.Bind.Propagation != "" {
		options = append(options, v.Bind.Propagation)

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. Upgrade Docker Engine to v28 or later (API 1.48+) and reconnect
  2. Verify the negotiated version: docker version --format '{{.Server.APIVersion}}'
  3. If upgrade is impossible, replace the image volume with a named volume plus an init step that copies content from the image
  4. Pin tooling that uses type: image to hosts with engine >= 28

Example fix

# before
volumes:
  - type: image
    source: alpine:latest
    target: /mnt/alpine
# after (engine < 28)
volumes:
  - mydata:/mnt/data
# plus: docker run --rm -v mydata:/t alpine sh -c 'cp -r /etc /t'
Defensive patterns

Strategy: validation

Validate before calling

// Go: check negotiated API version before relying on image volumes
ver, err := cli.ServerAPIVersion(ctx)
if err != nil { return err }
if versions.LessThan(ver, "1.48") {
    return fmt.Errorf("type=image volumes need Engine >= 28 (API 1.48), got %s", ver)
}

Prevention

When it happens

Trigger: A compose file with a volume entry whose type is 'image' (e.g. {type: image, source: alpine, target: /data}) run against an engine older than 28.0 (API < 1.48), e.g. Docker 27.x, older Docker Desktop, or an outdated remote DOCKER_HOST.

Common situations: Upgrading compose CLI but not the engine; CI runners pinned to an old docker engine; remote docker context pointing at an old host; feature was added in Engine 28 so older environments silently lack it.

Related errors


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