immich-app/immich · error · BadRequestException
Wrong password
Error message
Wrong password
What it means
changePassword first verifies the user's current password by comparing it against the stored bcrypt hash via validateSecret. If the supplied current password does not match, the update is aborted with a 400 'Wrong password' so an attacker with an open session cannot silently take over the account credentials.
Solutions
- Re-enter the correct current password and retry the change-password request.
- If the password is forgotten, use the password reset flow or have an admin reset it, then change it.
- Check that the user account actually authenticates locally (not solely via OAuth/LDAP) before attempting password change.
Example fix
// before
await api.authenticationApi.changePassword({ password: oldGuess, newPassword });
// after
const ok = await verifyCurrentPassword(oldGuess); // prompt again if false
if (ok) await api.authenticationApi.changePassword({ password: oldGuess, newPassword }); Defensive patterns
Strategy: try-catch
Validate before calling
if (!currentPassword || currentPassword.length === 0) {
throw new Error('Current password is required to change password');
} Try / catch
try {
await api.authenticationApi.changePassword({ password, newPassword });
} catch (e) {
if (e.status === 400 && e.message === 'Wrong password') {
// re-prompt user for current password
}
throw e;
} Prevention
- Always verify the current password with the user before submitting.
- Handle 'Wrong password' by re-prompting rather than retrying blindly (avoid lockouts).
- Sync password state across devices after a change.
When it happens
Trigger: Calling PUT /api/auth/password (changePassword) with a `password` field that does not match the user's currently stored password, even if `newPassword` is valid.
Common situations: User typo or caps-lock when re-entering the current password; password was changed on another device/session; client caching a stale password after a password reset; password managed by an external auth provider (OAuth/LDAP) so no local password matches.
Related errors
AI-assisted analysis of immich-app/immich@f48d4b3321 (2026-09-15).
Data as JSON: /api/errors/13168828d9a8cbf8.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/auth.service.ts:133
throw new BadRequestException('Invalid logout token: it must contain either a sub or a sid claim');
}
const deletedSessionIds = await this.sessionRepository.invalidateOAuth({
oauthSid: claims.sid,
oauthId: claims.sub,
});
for (const sessionId of deletedSessionIds) {
await this.eventRepository.emit('SessionDelete', { sessionId });
}
}
async changePassword(auth: AuthDto, dto: ChangePasswordDto): Promise<UserAdminResponseDto> {
const { password, newPassword } = dto;
const user = await this.userRepository.getForChangePassword(auth.user.id);
const isValid = this.validateSecret(password, user.password);
if (!isValid) {
throw new BadRequestException('Wrong password');
}
const hashedPassword = await this.cryptoRepository.hashBcrypt(newPassword, SALT_ROUNDS);
const updatedUser = await this.userRepository.update(user.id, {
password: hashedPassword,
shouldChangePassword: false,
});
await this.eventRepository.emit('AuthChangePassword', {
userId: user.id,
currentSessionId: auth.session?.id,
invalidateSessions: dto.invalidateSessions,
});
return mapUserAdmin(updatedUser);
}
View on GitHub (pinned to f48d4b3321)