phacility/phabricator · error · Exception

Analyzing or decrypting SSH keys requires the "ssh-keygen" b

Error message

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.

What it means

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.

Source

Thrown at src/applications/auth/sshkey/PhabricatorAuthSSHPrivateKey.php:38

  public function getPassphrase() {
    return $this->passphrase;
  }

  public static function newFromRawKey(PhutilOpaqueEnvelope $entire_key) {
    $key = new self();

    $key->body = $entire_key;

    return $key;
  }

  public function getKeyBody() {
    return $this->body;
  }

  public function newBarePrivateKey() {
    if (!Filesystem::binaryExists('ssh-keygen')) {
      throw new Exception(
        pht(
          '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.'));
    }

    $old_body = $this->body;

    // Some versions of "ssh-keygen" are sensitive to trailing whitespace for
    // some keys. Trim any trailing whitespace and replace it with a single
    // newline.
    $raw_body = $old_body->openEnvelope();
    $raw_body = rtrim($raw_body)."\n";
    $old_body = new PhutilOpaqueEnvelope($raw_body);

    $tmp = $this->newTemporaryPrivateKeyFile($old_body);

    // See T13454 for discussion of why this is so awkward. In broad strokes,

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Install the OpenSSH client: 'apt-get install openssh-client' (Debian/Ubuntu) or 'yum install openssh-clients' (RHEL/CentOS)
  2. Verify as the exact user running PHP/daemons: 'which ssh-keygen' must return a path
  3. Restart web server and phd daemons after installing or changing PATH so they pick up the new environment

Example fix

# before
$ sudo -u www-data which ssh-keygen
(no output)

# after
$ sudo apt-get install -y openssh-client
$ sudo -u www-data which ssh-keygen
/usr/bin/ssh-keygen
Defensive patterns

Strategy: validation

Validate before calling

// Cheap pre-flight before any private-key operation:
if (!Filesystem::binaryExists('ssh-keygen')) {
  // Fail with an actionable setup message instead of letting
  // newBarePrivateKey() throw mid-operation.
  throw new Exception(pht(
    'Install openssh-client on this host before testing SSH key credentials.'));
}

Try / catch

try {
  $bare_key = $private_key->newBarePrivateKey();
} catch (Exception $ex) {
  // ssh-keygen missing from PATH: report host setup problem,
  // not a key problem.
  $diagnostic = pht('Host lacks ssh-keygen; install openssh-client.');
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/875e6370e5b88b96. Report an issue: GitHub.