phacility/phabricator · error · PhabricatorApplicationTransactionValidationException

This contact number is already in use.

Error message

This contact number is already in use.

What it means

PhabricatorAuthContactNumberEditor catches the database duplicate-key exception (unique index on the contact number) during save and converts it into a PhabricatorApplicationTransactionValidationException attached to the number transaction type. It means another contact number row already holds the same canonicalized phone number, so each number must unambiguously identify one owner.

Source

Thrown at src/applications/auth/editor/PhabricatorAuthContactNumberEditor.php:34

  }

  public function getCreateObjectTitleForFeed($author, $object) {
    return pht('%s created %s.', $author, $object);
  }

  protected function didCatchDuplicateKeyException(
    PhabricatorLiskDAO $object,
    array $xactions,
    Exception $ex) {

    $errors = array();
    $errors[] = new PhabricatorApplicationTransactionValidationError(
      PhabricatorAuthContactNumberNumberTransaction::TRANSACTIONTYPE,
      pht('Duplicate'),
      pht('This contact number is already in use.'),
      null);

    throw new PhabricatorApplicationTransactionValidationException($errors);
  }


}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Search for the existing number first (PhabricatorAuthContactNumberQuery) and edit or delete that row instead of creating a new one.
  2. If the number should belong to a different user, delete it from the old contact first, then create it for the new one.
  3. In UI flows, render the validation error from PhabricatorApplicationTransactionValidationException on the number field so the user can correct it.

Example fix

// before: blindly create the number and hit the unique index
$number = PhabricatorAuthContactNumber::initializeNewContactNumber($user)
  ->setRawInputComponent('+15551234567');
$editor->applyTransactions($number, $xactions);

// after: check the unique key first and edit the existing row
$existing = id(new PhabricatorAuthContactNumberQuery())
  ->setViewer($viewer)
  ->withUniqueKeys(array($number->getUniqueKey()))
  ->executeOne();
if ($existing) {
  // edit or remove $existing instead of creating a duplicate
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check the unique key before creating a contact number
$unique_key = PhabricatorAuthContactNumber::newUniqueKeyFromNumber($raw_number);
$existing = id(new PhabricatorAuthContactNumberQuery())
  ->setViewer($viewer)
  ->withUniqueKeys(array($unique_key))
  ->executeOne();
if ($existing) {
  // edit or delete $existing instead of inserting
}

Try / catch

try {
  $editor->applyTransactions($number, $xactions);
} catch (PhabricatorApplicationTransactionValidationException $ex) {
  // Errors map to the number field; render them on the form.
  return $this->newDialog()->setValidationException($ex);
}

Prevention

When it happens

Trigger: Creating a new PhabricatorAuthContactNumber whose unique key (canonicalized dialing number) matches an existing row - same number on another user, a second 'primary' copy of your own number, or re-adding a number after a primary/duplicate adjustment where the row still exists.

Common situations: Users sharing a team phone; admins re-importing contact numbers; trying to move a number to a different account without first deleting/releasing it on the old one; retrying a submit that actually succeeded the first time.

Related errors


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