{"record":{"id":"875e6370e5b88b96","repo":"phacility/phabricator","slug":"analyzing-or-decrypting-ssh-keys-requires-the-ssh","errorCode":null,"errorMessage":"Analyzing or decrypting SSH keys requires the \"ssh-keygen\" binary, but it is not available in \"$PATH\". Make it available to work with SSH private keys.","messagePattern":"Analyzing or decrypting SSH keys requires the \"ssh-keygen\" binary, but it is not available in \"\\$PATH\"\\. Make it available to work with SSH private keys\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/auth/sshkey/PhabricatorAuthSSHPrivateKey.php","lineNumber":38,"sourceCode":"  public function getPassphrase() {\n    return $this->passphrase;\n  }\n\n  public static function newFromRawKey(PhutilOpaqueEnvelope $entire_key) {\n    $key = new self();\n\n    $key->body = $entire_key;\n\n    return $key;\n  }\n\n  public function getKeyBody() {\n    return $this->body;\n  }\n\n  public function newBarePrivateKey() {\n    if (!Filesystem::binaryExists('ssh-keygen')) {\n      throw new Exception(\n        pht(\n          'Analyzing or decrypting SSH keys requires the \"ssh-keygen\" binary, '.\n          'but it is not available in \"$PATH\". Make it available to work with '.\n          'SSH private keys.'));\n    }\n\n    $old_body = $this->body;\n\n    // Some versions of \"ssh-keygen\" are sensitive to trailing whitespace for\n    // some keys. Trim any trailing whitespace and replace it with a single\n    // newline.\n    $raw_body = $old_body->openEnvelope();\n    $raw_body = rtrim($raw_body).\"\\n\";\n    $old_body = new PhutilOpaqueEnvelope($raw_body);\n\n    $tmp = $this->newTemporaryPrivateKeyFile($old_body);\n\n    // See T13454 for discussion of why this is so awkward. In broad strokes,","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/auth/sshkey/PhabricatorAuthSSHPrivateKey.php#L20-L56","documentation":"PhabricatorAuthSSHPrivateKey::newBarePrivateKey() analyzes and decrypts SSH private keys by shelling out to ssh-keygen, so its first act is Filesystem::binaryExists('ssh-keygen'). If the binary is not on PATH for the PHP process, it throws before touching the key. This surfaces wherever Phabricator must open a private key: credential testing, repository cloning with SSH key auth, etc.","triggerScenarios":"Calling newBarePrivateKey() (directly or via credential test / Diffusion SSH auth) on a host without openssh-client installed, or where the web-server/daemon user's PATH does not include the directory containing ssh-keygen.","commonSituations":"Minimal Docker/CI containers that never installed openssh-client; phd daemons restarted with a sanitized PATH after a deploy; macOS or packaged PHP environments with a restricted default PATH.","solutions":["Install the OpenSSH client: 'apt-get install openssh-client' (Debian/Ubuntu) or 'yum install openssh-clients' (RHEL/CentOS)","Verify as the exact user running PHP/daemons: 'which ssh-keygen' must return a path","Restart web server and phd daemons after installing or changing PATH so they pick up the new environment"],"exampleFix":"# before\n$ sudo -u www-data which ssh-keygen\n(no output)\n\n# after\n$ sudo apt-get install -y openssh-client\n$ sudo -u www-data which ssh-keygen\n/usr/bin/ssh-keygen","handlingStrategy":"validation","validationCode":"// Cheap pre-flight before any private-key operation:\nif (!Filesystem::binaryExists('ssh-keygen')) {\n  // Fail with an actionable setup message instead of letting\n  // newBarePrivateKey() throw mid-operation.\n  throw new Exception(pht(\n    'Install openssh-client on this host before testing SSH key credentials.'));\n}","typeGuard":null,"tryCatchPattern":"try {\n  $bare_key = $private_key->newBarePrivateKey();\n} catch (Exception $ex) {\n  // ssh-keygen missing from PATH: report host setup problem,\n  // not a key problem.\n  $diagnostic = pht('Host lacks ssh-keygen; install openssh-client.');\n}","preventionTips":["Bake openssh-client into every container/image that runs Phabricator web or phd daemons","Verify 'which ssh-keygen' as the www-data/daemon user after deploys or PATH changes","Add a ssh-keygen availability check to install/upgrade smoke tests"],"tags":["ssh","ssh-keygen","phabricator","environment","path","missing-binary"],"backgroundTag":"missing-system-binary","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}