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
- Identify the colliding configs: query `SELECT id, providerClass, isEnabled FROM auth_providerconfig;` and look for two classes that map to the same adapter key.
- Disable or delete the duplicate config (the old class or the unmodified original) in the Auth application UI, or via SQL on auth_providerconfig.
- If both providers must coexist, override the adapter key in the custom subclass so getProviderKey() returns a unique value (see exampleFix).
- 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 subclassing a core auth provider, always override the adapter key to something unique.
- Remove old copies of renamed custom provider classes so both cannot be enabled at once.
- Test a login immediately after enabling any provider config in staging before production.
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Project icons must have unique keys, but two icons share the
- Both '%s' and '%s' define a custom field with field key '%s'
- Configuration file is not properly formatted JSON. %s
- Configuration file has improper configuration keys at top le
- Two servers (at indexes "%s" and "%s") both bind to the same
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/8c23c4acec0b0dcc.
Report an issue: GitHub.