phacility/phabricator · error · Exception

Credential "%s" must provide "%s", but provides "%s"!

Error message

Credential "%s" must provide "%s", but provides "%s"!

What it means

Thrown by PassphraseAbstractKey::validateCredential() when the credential's implementation provides a different capability than the caller requested: $type->getProvidesType() !== $provides_type. Credential types advertise what they provide ('ssh-key', 'token', 'password', ...), and consumers like PassphraseSSHKey require a specific provides-type, so handing a password or token credential to an SSH-key helper fails before any secret is opened.

Source

Thrown at src/applications/passphrase/keys/PassphraseAbstractKey.php:46

    return $credential;
  }

  private function validateCredential(
    PassphraseCredential $credential,
    $provides_type) {

    $type = $credential->getImplementation();

    if (!$type) {
      throw new Exception(
        pht(
          'Credential "%s" is of unknown type "%s"!',
          $credential->getMonogram(),
          $credential->getCredentialType()));
    }

    if ($type->getProvidesType() !== $provides_type) {
      throw new Exception(
        pht(
          'Credential "%s" must provide "%s", but provides "%s"!',
          $credential->getMonogram(),
          $provides_type,
          $type->getProvidesType()));
    }
  }

  protected function loadAndValidateFromPHID(
    $phid,
    PhabricatorUser $viewer,
    $type) {

    $credential = $this->loadCredential($phid, $viewer);

    $this->validateCredential($credential, $type);

    $this->credential = $credential;

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Create a credential of the correct kind (e.g. an 'SSH Private Key' credential) and reference its PHID instead.
  2. Filter credential chooser UIs by provides type so only compatible credentials are offered.
  3. If you implement a consumer, pass the PROVIDES_TYPE constant of the type you can actually consume.

Example fix

// before
$key = PassphraseSSHKey::loadFromPHID($password_credential_phid, $viewer);

// after
$credential = id(new PassphraseCredentialQuery())
  ->setViewer($viewer)
  ->withPHIDs(array($phid))
  ->executeOne();
if ($credential->getImplementation()->getProvidesType() !==
    PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE) {
  throw new Exception(
    pht('This workflow requires an SSH private key credential.'));
}
$key = PassphraseSSHKey::loadFromPHID($phid, $viewer);
Defensive patterns

Strategy: validation

Validate before calling

$credential = id(new PassphraseCredentialQuery())
  ->setViewer($viewer)
  ->withPHIDs(array($phid))
  ->executeOne();
if (!$credential ||
    $credential->getImplementation()->getProvidesType() !==
    PassphraseSSHPrivateKeyCredentialType::PROVIDES_TYPE) {
  // require an SSH-key credential instead
}

Type guard

function credential_provides($credential, $provides_type) {
  $type = $credential->getImplementation();
  return $type !== null && $type->getProvidesType() === $provides_type;
}

Try / catch

try {
  $key = PassphraseSSHKey::loadFromPHID($phid, $viewer);
} catch (Exception $ex) {
  if (preg_match('/must provide/', $ex->getMessage())) {
    // prompt user to select an SSH private key credential
  }
}

Prevention

When it happens

Trigger: Passing a password/token credential PHID to PassphraseSSHKey::loadFromPHID(), which validates against an SSH private-key provides type; wiring a generic token credential into a workflow that only understands SSH keys (e.g. Drydock SSH/working-copy blueprints).

Common situations: Configuration UIs that let users pick any credential instead of filtering by provides type; copying a PHID from an unrelated form field; blueprint templates reused across credential kinds.

Related errors


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