phacility/phabricator · critical · Exception

Two authentication providers use the same provider key ('%s'

Error message

Two authentication providers use the same provider key ('%s'). Each provider must be identified by a unique key.

What it means

Thrown while PhabricatorAuthProvider::getAllProviders() materializes every configured provider: each enabled PhabricatorAuthProviderConfig is instantiated, and its getProviderKey() (which returns the adapter's key, e.g. 'ldap' or 'jira') must be unique. If two installed provider classes produce the same adapter key, this Exception aborts provider construction. Because getAllProviders() backs all authentication pages, this typically breaks every login/config screen that touches auth providers.

Source

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

      $objects = self::getAllBaseProviders();

      $configs = id(new PhabricatorAuthProviderConfigQuery())
        ->setViewer(PhabricatorUser::getOmnipotentUser())
        ->execute();

      $providers = array();
      foreach ($configs as $config) {
        if (!isset($objects[$config->getProviderClass()])) {
          // This configuration is for a provider which is not installed.
          continue;
        }

        $object = clone $objects[$config->getProviderClass()];
        $object->attachProviderConfig($config);

        $key = $object->getProviderKey();
        if (isset($providers[$key])) {
          throw new Exception(
            pht(
              "Two authentication providers use the same provider key ".
              "('%s'). Each provider must be identified by a unique key.",
              $key));
        }
        $providers[$key] = $object;
      }
    }

    return $providers;
  }

  public static function getAllEnabledProviders() {
    $providers = self::getAllProviders();
    foreach ($providers as $key => $provider) {
      if (!$provider->isEnabled()) {
        unset($providers[$key]);
      }

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Identify the colliding configs: query `SELECT id, providerClass, isEnabled FROM auth_providerconfig;` and look for two classes that map to the same adapter key.
  2. Disable or delete the duplicate config (the old class or the unmodified original) in the Auth application UI, or via SQL on auth_providerconfig.
  3. If both providers must coexist, override the adapter key in the custom subclass so getProviderKey() returns a unique value (see exampleFix).
  4. After fixing, clear any static caches / restart PHP-FPM so the memoized getAllProviders() result is rebuilt, then verify the login page loads.

Example fix

// before — custom subclass inherits the parent adapter key, colliding with the core provider
class MyOrgLDAPAuthProvider extends PhabricatorLDAPAuthProvider {
  // no adapter override: getProviderKey() still returns 'ldap'
}

// after — give the custom provider its own adapter with a unique key
class MyOrgLDAPAuthProvider extends PhabricatorLDAPAuthProvider {
  public function getAdapter() {
    $adapter = parent::getAdapter();
    $adapter->setAdapterKey('myorg-ldap'); // unique across all providers
    return $adapter;
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// When shipping a custom provider, assert key uniqueness at install time
$base_keys = array();
foreach (PhabricatorAuthProvider::getAllBaseProviders() as $class => $provider) {
  $key = $provider->getProviderKey();
  if (isset($base_keys[$key])) {
    // class '$class' collides with '{$base_keys[$key]}' — override getAdapterKey()
  }
  $base_keys[$key] = $class;
}

Try / catch

try {
  $providers = PhabricatorAuthProvider::getAllProviders();
} catch (Exception $ex) {
  // duplicate provider key: this breaks ALL auth pages —
  // disable the offending config row immediately and page the on-call admin
}

Prevention

When it happens

Trigger: Enabling two provider configs whose classes share getAdapterKey() — most commonly a custom provider subclassed from a core provider (e.g. extending PhabricatorLDAPAuthProvider) without overriding the adapter, so both the parent and child report the same key; or two copies of the same custom provider class installed under different class names.

Common situations: A developer forks a core provider (LDAP, GitHub, etc.) to tweak behavior and enables both the original and the fork; a custom provider was renamed but the old class file is still autoloadable; duplicate configs left over after a class rename in an extension.

Understand the failure class

Related errors


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