{"record":{"id":"5dd19dfe48794e93","repo":"docker/compose","slug":"invalid-ssh-key-q","errorCode":null,"errorMessage":"invalid ssh key %q","messagePattern":"invalid ssh key %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/compose/build.go","lineNumber":58,"sourceCode":"\tpush       bool\n\targs       []string\n\tnoCache    bool\n\tmemory     cliopts.MemBytes\n\tssh        string\n\tbuilder    string\n\tdeps       bool\n\tprint      bool\n\tcheck      bool\n\tsbom       string\n\tprovenance string\n}\n\nfunc (opts buildOptions) toAPIBuildOptions(services []string) (api.BuildOptions, error) {\n\tvar SSHKeys []types.SSHKey\n\tif opts.ssh != \"\" {\n\t\tid, path, found := strings.Cut(opts.ssh, \"=\")\n\t\tif !found && id != \"default\" {\n\t\t\treturn api.BuildOptions{}, fmt.Errorf(\"invalid ssh key %q\", opts.ssh)\n\t\t}\n\t\tSSHKeys = append(SSHKeys, types.SSHKey{\n\t\t\tID:   id,\n\t\t\tPath: path,\n\t\t})\n\t}\n\tbuilderName := opts.builder\n\tif builderName == \"\" {\n\t\tbuilderName = os.Getenv(\"BUILDX_BUILDER\")\n\t}\n\n\tuiMode := display.Mode\n\tif uiMode == display.ModeJSON {\n\t\tuiMode = \"rawjson\"\n\t}\n\n\treturn api.BuildOptions{\n\t\tPull:       opts.pull,","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/cmd/compose/build.go#L40-L76","documentation":"--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.","triggerScenarios":"`docker compose build --ssh mykey` (missing =/path), or `--ssh default=/path` is fine but `--ssh path` alone (a bare path with no ID) fails.","commonSituations":"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.","solutions":["Use the ID=PATH form: `--ssh mykey=/home/me/.ssh/id_rsa`","Or use `--ssh default` to forward the SSH agent without naming a key","In scripts, build the flag as `--ssh \"id=$KEY_PATH\"` so the '=' is always present"],"exampleFix":"# before\ndocker compose build --ssh /home/me/.ssh/id_rsa\n# after\ndocker compose build --ssh default=/home/me/.ssh/id_rsa","handlingStrategy":"validation","validationCode":"# normalize --ssh before invoking compose\nssh_flag() {\n  case \"$1\" in\n    default) echo \"--ssh default\";;\n    *=*) echo \"--ssh $1\";;\n    *) echo \"--ssh default=$1\";;\n  esac\n}\ndocker compose build $(ssh_flag \"$SSH_ARG\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember the grammar: `default` or `id=path`, nothing else","Quote the whole flag so the '=' survives shell splitting"],"tags":["build","ssh","cli","flag-parsing"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}