docker/compose · error

invalid ssh key %q

Error message

invalid ssh key %q

What it means

--ssh expects either the bare keyword `default` (forward the agent) or an ID=PATH pair such as mykey=/home/me/.ssh/id_rsa. toAPIBuildOptions splits on '='; if there is no '=' and the value is not exactly 'default', the ID cannot be determined and build option construction fails before BuildKit is contacted.

Source

Thrown at cmd/compose/build.go:58

	push       bool
	args       []string
	noCache    bool
	memory     cliopts.MemBytes
	ssh        string
	builder    string
	deps       bool
	print      bool
	check      bool
	sbom       string
	provenance string
}

func (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, error) {
	var SSHKeys []types.SSHKey
	if opts.ssh != "" {
		id, path, found := strings.Cut(opts.ssh, "=")
		if !found && id != "default" {
			return api.BuildOptions{}, fmt.Errorf("invalid ssh key %q", opts.ssh)
		}
		SSHKeys = append(SSHKeys, types.SSHKey{
			ID:   id,
			Path: path,
		})
	}
	builderName := opts.builder
	if builderName == "" {
		builderName = os.Getenv("BUILDX_BUILDER")
	}

	uiMode := display.Mode
	if uiMode == display.ModeJSON {
		uiMode = "rawjson"
	}

	return api.BuildOptions{
		Pull:       opts.pull,

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. Use the ID=PATH form: `--ssh mykey=/home/me/.ssh/id_rsa`
  2. Or use `--ssh default` to forward the SSH agent without naming a key
  3. In scripts, build the flag as `--ssh "id=$KEY_PATH"` so the '=' is always present

Example fix

# before
docker compose build --ssh /home/me/.ssh/id_rsa
# after
docker compose build --ssh default=/home/me/.ssh/id_rsa
Defensive patterns

Strategy: validation

Validate before calling

# normalize --ssh before invoking compose
ssh_flag() {
  case "$1" in
    default) echo "--ssh default";;
    *=*) echo "--ssh $1";;
    *) echo "--ssh default=$1";;
  esac
}
docker compose build $(ssh_flag "$SSH_ARG")

Prevention

When it happens

Trigger: `docker compose build --ssh mykey` (missing =/path), or `--ssh default=/path` is fine but `--ssh path` alone (a bare path with no ID) fails.

Common situations: Users assuming --ssh takes just a path like some other tools; quoting mistakes that swallow the '='; CI scripts templating --ssh "$SSH_KEY" where the variable holds only a path.

Related errors


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