{"record":{"id":"8c23c4acec0b0dcc","repo":"phacility/phabricator","slug":"two-authentication-providers-use-the-same-provider","errorCode":null,"errorMessage":"Two authentication providers use the same provider key ('%s'). Each provider must be identified by a unique key.","messagePattern":"Two authentication providers use the same provider key \\('(.+?)'\\)\\. Each provider must be identified by a unique key\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"src/applications/auth/provider/PhabricatorAuthProvider.php","lineNumber":89,"sourceCode":"      $objects = self::getAllBaseProviders();\n\n      $configs = id(new PhabricatorAuthProviderConfigQuery())\n        ->setViewer(PhabricatorUser::getOmnipotentUser())\n        ->execute();\n\n      $providers = array();\n      foreach ($configs as $config) {\n        if (!isset($objects[$config->getProviderClass()])) {\n          // This configuration is for a provider which is not installed.\n          continue;\n        }\n\n        $object = clone $objects[$config->getProviderClass()];\n        $object->attachProviderConfig($config);\n\n        $key = $object->getProviderKey();\n        if (isset($providers[$key])) {\n          throw new Exception(\n            pht(\n              \"Two authentication providers use the same provider key \".\n              \"('%s'). Each provider must be identified by a unique key.\",\n              $key));\n        }\n        $providers[$key] = $object;\n      }\n    }\n\n    return $providers;\n  }\n\n  public static function getAllEnabledProviders() {\n    $providers = self::getAllProviders();\n    foreach ($providers as $key => $provider) {\n      if (!$provider->isEnabled()) {\n        unset($providers[$key]);\n      }","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/auth/provider/PhabricatorAuthProvider.php#L71-L107","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before — custom subclass inherits the parent adapter key, colliding with the core provider\nclass MyOrgLDAPAuthProvider extends PhabricatorLDAPAuthProvider {\n  // no adapter override: getProviderKey() still returns 'ldap'\n}\n\n// after — give the custom provider its own adapter with a unique key\nclass MyOrgLDAPAuthProvider extends PhabricatorLDAPAuthProvider {\n  public function getAdapter() {\n    $adapter = parent::getAdapter();\n    $adapter->setAdapterKey('myorg-ldap'); // unique across all providers\n    return $adapter;\n  }\n}","handlingStrategy":"validation","validationCode":"// When shipping a custom provider, assert key uniqueness at install time\n$base_keys = array();\nforeach (PhabricatorAuthProvider::getAllBaseProviders() as $class => $provider) {\n  $key = $provider->getProviderKey();\n  if (isset($base_keys[$key])) {\n    // class '$class' collides with '{$base_keys[$key]}' — override getAdapterKey()\n  }\n  $base_keys[$key] = $class;\n}","typeGuard":null,"tryCatchPattern":"try {\n  $providers = PhabricatorAuthProvider::getAllProviders();\n} catch (Exception $ex) {\n  // duplicate provider key: this breaks ALL auth pages —\n  // disable the offending config row immediately and page the on-call admin\n}","preventionTips":["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."],"tags":["phabricator","auth","configuration","duplicate-key","custom-provider"],"backgroundTag":"duplicate-provider-key","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}