phacility/phabricator · critical · Exception

Authentication provider (of class "%s") is attempting to loa

Error message

Authentication provider (of class "%s") is attempting to load or create an external account, but provided a list of account identifiers which map to more than one account: %s.

What it means

Thrown from PhabricatorAuthProvider::loadOrCreateExternalAccount() when the set of raw account identifiers the provider supplies (e.g. an LDAP DN plus an email address) matches more than one PhabricatorExternalAccount row for that provider config. The code deliberately refuses to guess which account is meant and raises this Exception instead of silently merging accounts. This signals a data-integrity problem: distinct external accounts ended up sharing an identifier.

Source

Thrown at src/applications/auth/provider/PhabricatorAuthProvider.php:223

    }

    $config = $this->getProviderConfig();
    $viewer = PhabricatorUser::getOmnipotentUser();

    $raw_identifiers = mpull($identifiers, 'getIdentifierRaw');

    $accounts = id(new PhabricatorExternalAccountQuery())
      ->setViewer($viewer)
      ->withProviderConfigPHIDs(array($config->getPHID()))
      ->withRawAccountIdentifiers($raw_identifiers)
      ->needAccountIdentifiers(true)
      ->execute();
    if (!$accounts) {
      $account = $this->newExternalAccount();
    } else if (count($accounts) === 1) {
      $account = head($accounts);
    } else {
      throw new Exception(
        pht(
          'Authentication provider (of class "%s") is attempting to load '.
          'or create an external account, but provided a list of '.
          'account identifiers which map to more than one account: %s.',
          get_class($this),
          implode(', ', $raw_identifiers)));
    }

    // See T13493. Add all the identifiers to the account. In the case where
    // an account initially has a lower-quality identifier (like an email
    // address) and later adds a higher-quality identifier (like a GUID), this
    // allows us to automatically upgrade toward the higher-quality identifier
    // and survive API changes which remove the lower-quality identifier more
    // gracefully.

    foreach ($identifiers as $identifier) {
      $account->appendIdentifier($identifier);
    }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Find the duplicates: `SELECT accountIndex, identifier, count(*) c FROM external_account_identifier WHERE identifier IN ('<id1>','<id2>') GROUP BY identifier HAVING c > 1;` and inspect the related phabricator_externalaccount rows for the provider config.
  2. Decide which external account is authoritative, then remove or correct the stale identifier rows (or reassign the userPHID) so each identifier maps to exactly one account — back up first.
  3. Re-attempt the login; the single remaining match loads normally and the identifier-upgrade path reattaches cleanly.
  4. If the duplicates belong to the same human, use the proper account-merge/admin tools rather than hand-editing, and check for orphaned sessions/tokens afterwards.
Defensive patterns

Strategy: try-catch

Validate before calling

// Detect ambiguity before login does: map each raw identifier to accounts
$accounts = id(new PhabricatorExternalAccountQuery())
  ->setViewer(PhabricatorUser::getOmnipotentUser())
  ->withProviderConfigPHIDs(array($config->getPHID()))
  ->withRawAccountIdentifiers($raw_identifiers)
  ->needAccountIdentifiers(true)
  ->execute();
if (count($accounts) > 1) {
  // deduplicate/repair external account identifier rows before proceeding
}

Try / catch

try {
  $account = $provider->loadOrCreateExternalAccount($config, $identifiers);
} catch (Exception $ex) {
  // identifiers map to multiple accounts: freeze automated login retries,
  // alert the user to contact an admin, and open a data-repair ticket
}

Prevention

When it happens

Trigger: A provider returns multiple identifiers (account GUID and email) where the GUID matches account A and the email matches account B under the same provider config; duplicate external_account rows were created by an earlier bug or interrupted login (T13493-era identifier upgrades); a user was migrated/imported twice.

Common situations: After an import or merge, two external accounts hold the same identifier; an LDAP server changed DN format so old and new identifiers both exist as separate accounts; a race between two concurrent logins created duplicate rows; the identifier upgrade path (adding higher-quality identifiers to an existing account) was interrupted midway.

Understand the failure class

Related errors


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