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

  1. Re-enter the correct current password and retry the change-password request.
  2. If the password is forgotten, use the password reset flow or have an admin reset it, then change it.
  3. 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

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)