{"record":{"id":"267d9c801993d582","repo":"SonarSource/sonarqube","slug":"user-s-doesn-t-exist-267d9c","errorCode":null,"errorMessage":"User '%s' doesn't exist","messagePattern":"User '(.+?)' doesn't exist","errorType":"exception","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UpdateIdentityProviderAction.java","lineNumber":161,"sourceCode":"    checkArgument(isAllowedProvider, \"Value of parameter 'newExternalProvider' (%s) must be one of: [%s] or [%s]\", newExternalProvider,\n      String.join(\", \", allowedIdentityProviders), String.join(\", \", \"LDAP\", \"LDAP_{serverKey}\"));\n  }\n\n  private List<String> getAvailableIdentityProviders() {\n    return identityProviderRepository.getAllEnabledAndSorted()\n      .stream()\n      .map(IdentityProvider::getKey)\n      .toList();\n  }\n\n  private static boolean isLdapIdentityProvider(String identityProviderKey) {\n    return identityProviderKey.startsWith(LDAP_SECURITY_REALM);\n  }\n\n  private UserDto getUser(DbSession dbSession, String login) {\n    UserDto user = dbClient.userDao().selectByLogin(dbSession, login);\n    if (user == null || !user.isActive()) {\n      throw new NotFoundException(format(\"User '%s' doesn't exist\", login));\n    }\n    return user;\n  }\n\n  private static UpdateUser toUpdateUser(UpdateIdentityProviderRequest request, UserDto user) {\n    return new UpdateUser()\n      .setExternalIdentityProvider(request.newExternalProvider)\n      .setExternalIdentityProviderLogin(Optional.ofNullable(request.newExternalIdentity).orElse(user.getExternalLogin())\n      );\n  }\n\n  private static UpdateIdentityProviderRequest toWsRequest(Request request) {\n    return UpdateIdentityProviderRequest.builder()\n      .setLogin(request.mandatoryParam(PARAM_LOGIN))\n      .setNewExternalProvider(replaceDeprecatedSonarqubeIdentityProviderByLdapForSonar17508(request.mandatoryParam(PARAM_NEW_EXTERNAL_PROVIDER)))\n      .setNewExternalIdentity(request.param(PARAM_NEW_EXTERNAL_IDENTITY))\n      .build();\n  }","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UpdateIdentityProviderAction.java#L143-L179","documentation":"UpdateIdentityProviderAction (api/users/update_identity_provider) throws this NotFoundException when the login supplied does not belong to an existing, active user. The action moves a user to a new identity provider (e.g. from LDAP realm to SAML/GitHub) and refuses to act on absent or deactivated accounts. Note: logins originating from the LDAP security realm carry a special prefix and cannot be relinked.","triggerScenarios":"POST api/users/update_identity_provider with a login that has no user row or has active=false; also attempting to relink a user whose identityProviderKey starts with the LDAP security realm prefix.","commonSituations":"Migrating authentication from LDAP to SAML/GitHub where some users never signed in and were never provisioned; user deactivated during offboarding but migration script still lists them; login mismatch after directory rename.","solutions":["Verify the login exists and is active (GET api/users/search) before running the identity-provider migration.","Reactivate the user (active=true) if it was disabled, then retry.","For users missing in the target IdP, provision them by having them sign in once with the new provider first, or create them via api/users/create.","Skip users whose identity is still managed by the LDAP security realm — they cannot be relinked via this endpoint."],"exampleFix":"// before: bulk migration blindly iterating a stale user list\nfor u in $USERS; do curl -su \"$ADMIN:\" -X POST \"https://sonar/api/users/update_identity_provider?login=$u&newIdentityProvider=saml\"; done\n// after: filter to active users first\ncurl -su \"$ADMIN:\" 'https://sonar/api/users/search?active=true' | jq -r '.users[].login'\nfor u in $ACTIVE_USERS; do curl -su \"$ADMIN:\" -X POST \"https://sonar/api/users/update_identity_provider?login=$u&newIdentityProvider=saml\"; done","handlingStrategy":"validation","validationCode":"const {users} = await fetch(`${base}/api/users/search?q=${encodeURIComponent(login)}`, {headers: auth}).then(r => r.json());\nconst user = users.find(u => u.login === login && u.active);\nif (!user) throw new Error(`cannot relink ${login}: missing or inactive`);\nif (user.externalProvider === 'ldap' || user.externalProvider === 'sonarqube-ldap') throw new Error('LDAP realm identity cannot be relinked');","typeGuard":"function canRelinkIdentity(u) {\n  return u != null && u.active === true && !/^ldap/i.test(String(u.externalProvider ?? ''));\n}","tryCatchPattern":"try {\n  await updateIdentityProvider(login, newProvider);\n} catch (e) {\n  if (e.status === 404 && /doesn't exist/.test(e.message)) {\n    migrations.push({login, reason: 'missing-or-inactive'}); // handle out of band\n    return;\n  }\n  throw e;\n}","preventionTips":["Pre-check user existence and active status before IdP migrations","Skip or provision users missing from the new IdP before relinking","Exclude LDAP-realm identities from migration lists","Have target-IdP users sign in once to self-provision before relinking"],"tags":["sonarqube","rest-api","sso","identity-provider"],"backgroundTag":"user-not-found","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}