immich-app/immich · error · BadRequestException
Wrong password
Error message
Wrong password
What it means
Thrown by AuthService.changePassword (POST /auth/change-password) when validateSecret(password, user.password) fails, i.e. the supplied current password does not match the stored bcrypt hash. The user is fetched via getForChangePassword(auth.user.id) so it always exists; only the current-password check can fail, yielding 400 BadRequest 'Wrong password'.
Source
Thrown at server/src/services/auth.service.ts:132
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 });
await this.eventRepository.emit('AuthChangePassword', {
userId: user.id,
currentSessionId: auth.session?.id,
invalidateSessions: dto.invalidateSessions,
});
return mapUserAdmin(updatedUser);
}
async setupPinCode(auth: AuthDto, { pinCode }: PinCodeSetupDto) {
const user = await this.userRepository.getForPinCode(auth.user.id);
if (!user) {View on GitHub (pinned to 199723261c)
Solutions
- Confirm the current password is correct (re-enter, check caps).
- Ensure the request body maps password -> current and newPassword -> new exactly as the DTO expects.
- If forgotten, use the admin reset / forgot-password flow instead of change-password.
Example fix
// before
await api.post('/auth/change-password', { password: newPassword, newPassword: currentPassword });
// after
await api.post('/auth/change-password', { password: currentPassword, newPassword }); Defensive patterns
Strategy: try-catch
Validate before calling
// Map fields exactly as the DTO expects; validate non-empty.
if (!dto.password || !dto.newPassword) {
throw new Error('Both current and new password are required.');
}
if (dto.password === dto.newPassword) {
throw new Error('New password must differ from the current password.');
}
await api.post('/auth/change-password', { password: dto.password, newPassword: dto.newPassword }); Try / catch
try {
await api.post('/auth/change-password', { password, newPassword });
} catch (e) {
if (e.response?.status === 400 && /wrong password/i.test(e.response?.data?.message)) {
showCurrentPasswordError();
} else throw e;
} Prevention
- Keep field order explicit: password = current, newPassword = new.
- Confirm the current password before submit; offer reset if forgotten.
- Beware concurrent password changes invalidating the old password.
When it happens
Trigger: POST /auth/change-password where the 'password' (current) field is incorrect; user changed password elsewhere and the cached credential is stale; password field order swapped with newPassword in the request body.
Common situations: User mistypes the current password; client sends fields in the wrong order (newPassword in the password slot); concurrent password change invalidating the old password.
Related errors
- Incorrect email or password
- Error backchannel logout: token validation failed
- User already has a PIN code
- User does not have a PIN code
- Either password or pinCode is required
AI-assisted analysis of immich-app/immich@199723261c (2026-08-12).
Data as JSON: /api/errors/13168828d9a8cbf8.
Report an issue: GitHub.