{"record":{"id":"407497790d0647f4","repo":"oven-sh/bun","slug":"failed-to-generate-ssh-key-privatepath-pub","errorCode":null,"errorMessage":"Failed to generate SSH key: ${privatePath} / ${publicPath}","messagePattern":"Failed to generate SSH key: (.+?) / (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/machine.mjs","lineNumber":851,"sourceCode":" * @property {string} publicKey\n */\n\n/**\n * @returns {SshKey}\n */\nfunction createSshKey() {\n  const sshKeyGen = which(\"ssh-keygen\", { required: true });\n  const sshAdd = which(\"ssh-add\", { required: true });\n\n  const sshPath = join(homedir(), \".ssh\");\n  mkdir(sshPath);\n\n  const filename = `id_rsa_${crypto.randomUUID()}`;\n  const privatePath = join(sshPath, filename);\n  const publicPath = join(sshPath, `${filename}.pub`);\n  spawnSyncSafe([sshKeyGen, \"-t\", \"rsa\", \"-b\", \"4096\", \"-f\", privatePath, \"-N\", \"\"], { stdio: \"inherit\" });\n  if (!existsSync(privatePath) || !existsSync(publicPath)) {\n    throw new Error(`Failed to generate SSH key: ${privatePath} / ${publicPath}`);\n  }\n\n  if (isWindows) {\n    spawnSyncSafe([sshAdd, privatePath], { stdio: \"inherit\" });\n  } else {\n    const sshAgent = which(\"ssh-agent\");\n    if (sshAgent) {\n      spawnSyncSafe([\"sh\", \"-c\", `eval $(${sshAgent} -s) && ${sshAdd} ${privatePath}`], { stdio: \"inherit\" });\n    }\n  }\n\n  return {\n    privatePath,\n    publicPath,\n    get publicKey() {\n      return readFile(publicPath, { cache: true });\n    },\n  };","sourceCodeStart":833,"sourceCodeEnd":869,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/scripts/machine.mjs#L833-L869","documentation":"createSshKey() locates ssh-keygen via `which(required:true)`, runs `ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_<uuid> -N ''` with inherited stdio, then requires both the private and .pub files to exist. The throw means ssh-keygen ran but produced no key files (its real error was printed to your terminal by the inherited stdio).","triggerScenarios":"~/.ssh (from homedir()) not writable or HOME unset/odd in a CI container; ssh-keygen exiting non-zero (disk full, unsupported options, permission denied on the output path) while spawnSyncSafe continues; path length or filesystem issues on Windows.","commonSituations":"CI container running with a read-only or missing home; HOME pointing somewhere unexpected; corporate antivirus locking the file on Windows.","solutions":["Reproduce manually: `ssh-keygen -t rsa -b 4096 -f ~/.ssh/testkey -N ''`","Check `echo $HOME`, ensure ~/.ssh exists and is writable (mkdir is already attempted — look for its failure)","Inspect the ssh-keygen stderr that was printed with stdio: 'inherit' just before the throw","Free disk space / fix permissions on the home directory"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Verify the prerequisites createSshKey assumes\nif (!existsSync(join(homedir(), '.ssh'))) {\n  throw new Error(`~/.ssh missing and HOME=${homedir()} may be wrong for this container`);\n}\nBun.spawnSync(['ssh-keygen', '--help'], { stdout: 'ignore', stderr: 'ignore' });","typeGuard":null,"tryCatchPattern":"try {\n  sshKeys = createSshKey();\n} catch (error) {\n  // The inherited stdio already printed ssh-keygen's reason; surface HOME context\n  throw new Error(`SSH key generation failed (HOME=${homedir()}): ${error}`);\n}","preventionTips":["Run CI containers with a writable HOME and ssh-keygen installed","Watch the inherited ssh-keygen output right before this throw — it names the cause","Check disk space and ~/.ssh permissions when key generation inexplicably fails"],"tags":["ssh","local-env","provisioning","filesystem"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}