phacility/phabricator · warning · PhutilArgumentUsageException

User account "%s" is already approved. You can only approve

Error message

User account "%s" is already approved. You can only approve accounts that are not yet approved.

What it means

Thrown by the Phabricator people-management CLI (`bin/people approve --user <username>`) when the target account's isApproved flag is already true. The approve workflow refuses to apply a no-op approval transaction, so management commands always represent a real state change. The account is already in the requested state, so the command exits with a PhutilArgumentUsageException instead of writing transactions.

Source

Thrown at src/applications/people/management/PhabricatorPeopleManagementApproveWorkflow.php:24

  protected function didConstruct() {
    $arguments = array_merge(
      $this->getUserSelectionArguments(),
      array());

    $this
      ->setName('approve')
      ->setExamples('**approve** --user __username__')
      ->setSynopsis(pht('Approves a user.'))
      ->setArguments($arguments);
  }

  public function execute(PhutilArgumentParser $args) {
    $user = $this->selectUser($args);
    $display_name = $user->getUsername();

    if ($user->getIsApproved()) {
      throw new PhutilArgumentUsageException(
        pht(
          'User account "%s" is already approved. You can only '.
          'approve accounts that are not yet approved.',
          $display_name));
    }

    $xactions = array();
    $xactions[] = $user->getApplicationTransactionTemplate()
      ->setTransactionType(PhabricatorUserApproveTransaction::TRANSACTIONTYPE)
      ->setNewValue(true);

    $this->applyTransactions($user, $xactions);

    $this->logOkay(
      pht('DONE'),
      pht('Approved user account "%s".', $display_name));

    return 0;

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. No fix required - the account is already approved; confirm on the People > username profile page
  2. If scripting bulk approvals, query the current state first (PhabricatorPeopleQuery or Conduit user.query) and skip users where isApproved is true
  3. Treat this specific usage exception as success (idempotent no-op) in automation by checking state beforehand or matching the message

Example fix

# before
./bin/people approve --user alice
# after (idempotent script guard)
./bin/people approve --user "$USERNAME" 2>&1 | grep -q 'already approved' \
  && echo "$USERNAME: already approved (ok)"
Defensive patterns

Strategy: validation

Validate before calling

// Resolve the user and check approval state before invoking the workflow
$user = id(new PhabricatorPeopleQuery())
  ->setViewer($viewer)
  ->withUsernames(array($username))
  ->executeOne();
if (!$user || $user->getIsApproved()) {
  return; // nothing to approve
}

Type guard

function isAlreadyApproved(PhabricatorUser $user) {
  return (bool)$user->getIsApproved();
}

Prevention

When it happens

Trigger: Running `./bin/people approve --user alice` when alice is already approved; re-running a bulk onboarding/approval script over already-approved users; approving an account that was already approved through the admin UI or a previous CLI run.

Common situations: Bulk-approval automation re-executed without state checks; operators 'verifying' approval took effect by re-running the command; installs where accounts get auto-approved (e.g. by email verification) and an admin tries to approve manually.

Related errors


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