SonarSource/sonarqube · error · NotFoundException
User '%s' doesn't exist
Error message
User '%s' doesn't exist
What it means
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.
Source
Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UpdateIdentityProviderAction.java:161
checkArgument(isAllowedProvider, "Value of parameter 'newExternalProvider' (%s) must be one of: [%s] or [%s]", newExternalProvider,
String.join(", ", allowedIdentityProviders), String.join(", ", "LDAP", "LDAP_{serverKey}"));
}
private List<String> getAvailableIdentityProviders() {
return identityProviderRepository.getAllEnabledAndSorted()
.stream()
.map(IdentityProvider::getKey)
.toList();
}
private static boolean isLdapIdentityProvider(String identityProviderKey) {
return identityProviderKey.startsWith(LDAP_SECURITY_REALM);
}
private UserDto getUser(DbSession dbSession, String login) {
UserDto user = dbClient.userDao().selectByLogin(dbSession, login);
if (user == null || !user.isActive()) {
throw new NotFoundException(format("User '%s' doesn't exist", login));
}
return user;
}
private static UpdateUser toUpdateUser(UpdateIdentityProviderRequest request, UserDto user) {
return new UpdateUser()
.setExternalIdentityProvider(request.newExternalProvider)
.setExternalIdentityProviderLogin(Optional.ofNullable(request.newExternalIdentity).orElse(user.getExternalLogin())
);
}
private static UpdateIdentityProviderRequest toWsRequest(Request request) {
return UpdateIdentityProviderRequest.builder()
.setLogin(request.mandatoryParam(PARAM_LOGIN))
.setNewExternalProvider(replaceDeprecatedSonarqubeIdentityProviderByLdapForSonar17508(request.mandatoryParam(PARAM_NEW_EXTERNAL_PROVIDER)))
.setNewExternalIdentity(request.param(PARAM_NEW_EXTERNAL_IDENTITY))
.build();
}View on GitHub (pinned to 184c821202)
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.
Example fix
// before: bulk migration blindly iterating a stale user list for u in $USERS; do curl -su "$ADMIN:" -X POST "https://sonar/api/users/update_identity_provider?login=$u&newIdentityProvider=saml"; done // after: filter to active users first curl -su "$ADMIN:" 'https://sonar/api/users/search?active=true' | jq -r '.users[].login' for u in $ACTIVE_USERS; do curl -su "$ADMIN:" -X POST "https://sonar/api/users/update_identity_provider?login=$u&newIdentityProvider=saml"; done
Defensive patterns
Strategy: validation
Validate before calling
const {users} = await fetch(`${base}/api/users/search?q=${encodeURIComponent(login)}`, {headers: auth}).then(r => r.json());
const user = users.find(u => u.login === login && u.active);
if (!user) throw new Error(`cannot relink ${login}: missing or inactive`);
if (user.externalProvider === 'ldap' || user.externalProvider === 'sonarqube-ldap') throw new Error('LDAP realm identity cannot be relinked'); Type guard
function canRelinkIdentity(u) {
return u != null && u.active === true && !/^ldap/i.test(String(u.externalProvider ?? ''));
} Try / catch
try {
await updateIdentityProvider(login, newProvider);
} catch (e) {
if (e.status === 404 && /doesn't exist/.test(e.message)) {
migrations.push({login, reason: 'missing-or-inactive'}); // handle out of band
return;
}
throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "User not found", "Invalid user", and "does not exist": what missing-user lookup errors mean across Rocket.Chat, LiteLLM, Phabricator, rustfs, and pnpm — this error's family across 10 libraries.
Related errors
- Identity provider %s does not exist or is not enabled
- User with login '%s' has not been found
- parameter %s requires Administer System permission.
- Unknown type '%s'
- User '%s' doesn't exist
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/267d9c801993d582.
Report an issue: GitHub.