phacility/phabricator · error · Exception

Email record has invalid user PHID!

Error message

Email record has invalid user PHID!

What it means

Thrown by `bin/auth verify` when the email row exists but its userPHID column does not resolve to any real user. After loading the PhabricatorUserEmail record, the workflow queries PhabricatorPeopleQuery with that PHID; a null result raises this generic Exception (not a usage exception), because the cause is data corruption rather than operator input: an email record pointing at a missing user. The verification editor is never invoked, so nothing is written.

Source

Thrown at src/applications/auth/management/PhabricatorAuthManagementVerifyWorkflow.php:52

    $email = id(new PhabricatorUserEmail())->loadOneWhere(
      'address = %s',
      $address);
    if (!$email) {
      throw new PhutilArgumentUsageException(
        pht(
          'No email exists with address "%s"!',
          $address));
    }

    $viewer = $this->getViewer();

    $user = id(new PhabricatorPeopleQuery())
      ->setViewer($viewer)
      ->withPHIDs(array($email->getUserPHID()))
      ->executeOne();
    if (!$user) {
      throw new Exception(pht('Email record has invalid user PHID!'));
    }

    $editor = id(new PhabricatorUserEditor())
      ->setActor($viewer)
      ->verifyEmail($user, $email);

    $console = PhutilConsole::getConsole();

    $console->writeOut(
      "%s\n",
      pht('Done.'));

    return 0;
  }

}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Inspect the orphan: `SELECT e.phid, e.address, e.userPHID FROM user_email e LEFT JOIN user u ON u.phid = e.userPHID WHERE e.address = '<address>';` — the join will show NULL on the user side.
  2. If the user was deleted intentionally, remove the orphaned email row (or use the proper user-removal workflow to purge it), since the address can no longer be verified for anyone.
  3. If the user should exist, repair the userPHID to point at the correct user row and re-run `bin/auth verify <address>`.
  4. Audit for more orphans with `SELECT e.userPHID FROM user_email e LEFT JOIN user u ON u.phid=e.userPHID WHERE u.phid IS NULL;`.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-flight: detect the orphan before invoking the workflow
$user = id(new PhabricatorPeopleQuery())
  ->setViewer(PhabricatorUser::getOmnipotentUser())
  ->withPHIDs(array($email->getUserPHID()))
  ->executeOne();
if (!$user) {
  // orphaned email row: repair or delete it before running verify
}

Try / catch

try {
  $err = id(new PhabricatorUserEditor())
    ->setActor($viewer)
    ->verifyEmail($user, $email);
} catch (Exception $ex) {
  // 'Email record has invalid user PHID!' means data corruption:
  // log it, halt the batch, and queue a manual repair of user_email.userPHID
}

Prevention

When it happens

Trigger: Running `bin/auth verify <address>` where the user_email row references a PHID of a deleted/purged user, a PHID mangled by a partial import or manual SQL edit, or a user record removed while their email rows survived.

Common situations: Users were deleted with `bin/remove destroy` but orphaned user_email rows remained; a database migration or restore left referential integrity broken; someone edited user rows by hand in production.

Related errors


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