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.
Solutions
- Search for the existing number first (PhabricatorAuthContactNumberQuery) and edit or delete that row instead of creating a new one.
- If the number should belong to a different user, delete it from the old contact first, then create it for the new one.
- 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
- Treat contact numbers as globally unique values; search before creating.
- Move a number between owners by deleting and re-creating in one operation, not by duplicate inserts.
- Always render PhabricatorApplicationTransactionValidationException in UI flows so users see the field error.
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
- Phone number (" ") is not in a recognized format: expected…
- This public key is already associated with another user or…
- Another namespace with this name already exists. Each…
- Both ' ' and ' ' define a custom field with field key ' '…
- Device " " is unrecognized, restricted, or you do not have…
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/70a730e7c25cf76b.
Report an issue: GitHub.
Appendix: 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)