SonarSource/sonarqube · error · NotFoundException
User with login '%s' has not been found
Error message
User with login '%s' has not been found
What it means
SonarQube's user web API (ChangePasswordAction) throws this NotFoundException when the login passed to the change-password endpoint does not resolve to an existing AND active user. The DAO selectByLogin returns null for missing users, and deactived users are treated the same as missing ones so their credentials cannot be manipulated. It is the API's way of saying the target account is absent or disabled.
Source
Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/ChangePasswordAction.java:206
private void checkPreviousPassword(DbSession dbSession, UserDto user, String password) throws PasswordException {
try {
localAuthentication.authenticate(dbSession, user, password, AuthenticationEvent.Method.BASIC);
} catch (AuthenticationException ex) {
throw new PasswordException(OLD_PASSWORD_INCORRECT, "Incorrect password");
}
}
private static void checkNewPasswordSameAsOld(String newPassword, String previousPassword) throws PasswordException {
if (previousPassword.equals(newPassword)) {
throw new PasswordException(NEW_PASSWORD_SAME_AS_OLD, "Password must be different from old password");
}
}
private UserDto getUserOrThrow(DbSession dbSession, String login) {
UserDto user = dbClient.userDao().selectByLogin(dbSession, login);
if (user == null || !user.isActive()) {
throw new NotFoundException(format("User with login '%s' has not been found", login));
}
return user;
}
private void deleteTokensAndRefreshSession(HttpRequest request, HttpResponse response, DbSession dbSession, UserDto user) {
dbClient.sessionTokensDao().deleteByUser(dbSession, user);
refreshJwtToken(request, response, user);
}
private void refreshJwtToken(HttpRequest request, HttpResponse response, UserDto user) {
jwtHttpHandler.removeToken(request, response);
jwtHttpHandler.generateToken(user, request, response);
}
private void updatePassword(DbSession dbSession, UserDto user, String newPassword) {
UpdateUser updateUser = new UpdateUser().setPassword(newPassword);
userUpdater.updateAndCommit(dbSession, user, updateUser, u -> {
});View on GitHub (pinned to 184c821202)
Solutions
- Verify the login exists and is active: GET api/users/search?q=<login> as an administrator, and confirm the 'login' field (not name or email).
- If the user is deactivated, reactivate first via POST api/users/update with active=true (requires Administer System).
- Create the user if missing: POST api/users/create with the correct login, then retry the password change.
- If login identity comes from an external auth (LDAP/SAML/GitHub), the login may be provisioned on first sign-in — have the user sign in once, then retry.
- Check for whitespace/case issues in the login parameter; logins are stored exactly as created.
Example fix
// before: querying by email instead of login curl -u admin:token -X POST 'https://sonar/api/users/change_password?login=jane@corp.com&password=...' // after: use the actual login, after verifying it exists curl -u admin:token 'https://sonar/api/users/search?q=jdoe' # find exact login curl -u admin:token -X POST 'https://sonar/api/users/change_password?login=jdoe&password=...'
Defensive patterns
Strategy: validation
Validate before calling
const exists = await fetch(`${base}/api/users/search?q=${encodeURIComponent(login)}`, {headers: auth});
const {users} = await exists.json();
const user = users.find(u => u.login === login && u.active);
if (!user) throw new Error(`login ${login} missing or inactive; aborting change_password`); Type guard
function isActiveUser(u) {
return u != null && typeof u.login === 'string' && u.active === true;
} Try / catch
try {
await changePassword(login, newPassword);
} catch (e) {
if (e.status === 404 && /has not been found/.test(e.message)) {
// user missing or deactivated: look it up / reactivate before retry
} else throw e;
} Prevention
- Resolve logins via api/users/search instead of hardcoding them
- Treat deactivated users as not-found in pre-checks
- Use the login field, never name or email
- Account for SSO first-sign-in provisioning delays
When it happens
Trigger: POST api/users/change_password with a 'login' parameter that matches no user row, or matches a user whose active=false.
Common situations: Typo in login; user was deactivated/deleted by an admin; referring to a user by name or email instead of login; user was removed after token/credential cleanup scripts; SAML/LDAP-provisioned account not yet created locally.
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
- User '%s' doesn't exist
- User '%s' doesn't exist
- Cannot create unique login for user name
- Project '%s' not found
- Issue with key '%s' does not exist
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/c7d44b2cd41207a9.
Report an issue: GitHub.