{"record":{"id":"1b1c02cc60cb74a5","repo":"phacility/phabricator","slug":"only-private-key-credentials-are-supported","errorCode":null,"errorMessage":"Only private key credentials are supported.","messagePattern":"Only private key credentials are supported\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php","lineNumber":20,"sourceCode":"\nfinal class DrydockSFTPFilesystemInterface extends DrydockFilesystemInterface {\n\n  private $passphraseSSHKey;\n\n  private function openCredentialsIfNotOpen() {\n    if ($this->passphraseSSHKey !== null) {\n      return;\n    }\n\n    $credential = id(new PassphraseCredentialQuery())\n      ->setViewer(PhabricatorUser::getOmnipotentUser())\n      ->withIDs(array($this->getConfig('credential')))\n      ->needSecrets(true)\n      ->executeOne();\n\n    if ($credential->getProvidesType() !==\n      PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE) {\n      throw new Exception(pht('Only private key credentials are supported.'));\n    }\n\n    $this->passphraseSSHKey = PassphraseSSHKey::loadFromPHID(\n      $credential->getPHID(),\n      PhabricatorUser::getOmnipotentUser());\n  }\n\n  private function getExecFuture($path) {\n    $this->openCredentialsIfNotOpen();\n\n    return new ExecFuture(\n      'sftp -o \"StrictHostKeyChecking no\" -P %s -i %P %P@%s',\n      $this->getConfig('port'),\n      $this->passphraseSSHKey->getKeyfileEnvelope(),\n      $this->passphraseSSHKey->getUsernameEnvelope(),\n      $this->getConfig('host'));\n  }\n","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php#L2-L38","documentation":"Thrown by DrydockSFTPFilesystemInterface when the credential configured for an SFTP interface is not an SSH private key credential. The interface loads the credential by ID from blueprint/lease config (getConfig('credential')), requires its secrets, and checks getProvidesType() against PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE because the sftp command line is assembled with a private key file (-i). Any other Passphrase credential type (password, token, etc.) is rejected.","triggerScenarios":"A host blueprint or lease declares an SFTP filesystem interface whose 'credential' config points at a Passphrase credential of the wrong provides-type (e.g. a password credential or an SSH public key). The first call to openCredentialsIfNotOpen()/getExecFuture() throws before any sftp command runs.","commonSituations":"Reusing an existing generic/password credential instead of creating an SSH key credential; pasting a credential ID from another blueprint without checking its type; rotating credentials and replacing the SSH key credential with a different type under the same name.","solutions":["Create an SSH private key credential in Passphrase (type 'ssh-key' / provides type of PassphraseSSHPrivateKeyCredentialType) containing the key used to authenticate to the SFTP host.","Update the blueprint's credential config (the 'credential' key, a credential ID) to the new credential's ID and re-acquire the lease/resource.","Verify the choice programmatically: load the credential and assert getProvidesType() matches PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE before configuring."],"exampleFix":"// before: blueprint 'credential' config points at a password credential\n// (PassphraseSSHPasswordCredentialType) -> throws\n\n// after: create an ssh-key credential, e.g.\n//   passphrase.credential.create with type 'ssh-key', then\n$this->setConfig('credential', $ssh_key_credential->getID());","handlingStrategy":"validation","validationCode":"$credential = id(new PassphraseCredentialQuery())\n  ->setViewer($viewer)\n  ->withIDs(array($credential_id))\n  ->executeOne();\nif (!$credential ||\n    $credential->getProvidesType() !==\n      PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE) {\n  throw new InvalidArgumentException(\n    'SFTP interfaces require an SSH private key credential.');\n}","typeGuard":"function isSSHKeyCredential(PassphraseCredential $credential) {\n  return $credential->getProvidesType()\n    === PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE;\n}","tryCatchPattern":null,"preventionTips":["Adopt a naming convention for credentials (e.g. prefix 'ssh-') so key credentials are distinguishable at a glance.","Validate the credential type in blueprint configuration UI/scripts before any lease is acquired, not at first SFTP use."],"tags":["drydock","phabricator","sftp","passphrase","credential","ssh-key"],"backgroundTag":"credential-type-mismatch","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}