phacility/phabricator · error · PhutilArgumentUsageException

You can only trust keys associated with Almanac devices.

Error message

You can only trust keys associated with Almanac devices.

What it means

Thrown by the Almanac 'trust-key' management workflow when the SSH public key selected with --id is attached to an object that is not an AlmanacDevice. Phabricator only permits trusting device keys, because a trusted private key lets the host sign cluster-internal requests that bypass policy and security checks. The check runs after the key was found, confirmed active, and confirmed not yet trusted.

Source

Thrown at src/applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php:49

      ->withIDs(array($id))
      ->executeOne();
    if (!$key) {
      throw new PhutilArgumentUsageException(
        pht('No public key exists with ID "%s".', $id));
    }

    if (!$key->getIsActive()) {
      throw new PhutilArgumentUsageException(
        pht('Public key "%s" is not an active key.', $id));
    }

    if ($key->getIsTrusted()) {
      throw new PhutilArgumentUsageException(
        pht('Public key with ID %s is already trusted.', $id));
    }

    if (!($key->getObject() instanceof AlmanacDevice)) {
      throw new PhutilArgumentUsageException(
        pht('You can only trust keys associated with Almanac devices.'));
    }

    $handle = id(new PhabricatorHandleQuery())
      ->setViewer($this->getViewer())
      ->withPHIDs(array($key->getObject()->getPHID()))
      ->executeOne();

    $console->writeOut(
      "**<bg:red> %s </bg>**\n\n%s\n\n%s\n\n%s",
      pht('IMPORTANT!'),
      phutil_console_wrap(
        pht(
          'Trusting a public key gives anyone holding the corresponding '.
          'private key complete, unrestricted access to all data. The '.
          'private key will be able to sign requests that bypass policy and '.
          'security checks.')),
      phutil_console_wrap(

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Look up the SSH key that is actually attached to the device (open the device record in Almanac and use its key's ID) and re-run trust-key with that ID.
  2. If the device has no key yet, generate/add an SSH key on the device record first, then run ./bin/almanac trust-key --id <newID>.
  3. Before trusting, verify the key's attached object is an AlmanacDevice (its object row/attachment), so you know you picked the right ID.
  4. Accept the restriction: user keys cannot and should not be trusted; this workflow refusing them is by design.
Defensive patterns

Strategy: validation

Validate before calling

// Before invoking the trust workflow, confirm the key belongs to a device:
$key = id(new PhabricatorAuthSSHKeyQuery())
  ->setViewer($viewer)
  ->withIDs(array($id))
  ->executeOne();
if (!$key) {
  throw new Exception("No SSH key with ID {$id}.");
}
if (!($key->getObject() instanceof AlmanacDevice)) {
  throw new Exception("Key {$id} belongs to a non-device object; refusing to trust.");
}
// Safe to proceed with trust-key.

Type guard

function isDeviceSSHKey(PhabricatorAuthSSHKey $key) {
  return $key->getObject() instanceof AlmanacDevice;
}

Try / catch

try {
  // run trust-key workflow / PhutilArgumentParser->executeWorkFlow
} catch (PhutilArgumentUsageException $ex) {
  // Usage/eligibility failure: print and exit non-zero; key state is unchanged.
  fwrite(STDERR, $ex->getMessage()."\n");
  exit(1);
}

Prevention

When it happens

Trigger: Running ./bin/almanac trust-key --id N where key N's objectPHID points at a PhabricatorUser (a key a person added under Settings > SSH Public Keys) or any other non-device object. The isActive and isTrusted guards pass, then $key->getObject() instanceof AlmanacDevice fails at src/applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php:49.

Common situations: An admin lists SSH keys in the auth UI and copies a user's key ID instead of the device's key ID; the device never had a key generated for it; attempting to trust a service account's key. Trigger is always operator-side key selection, not corruption.

Related errors


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