langgenius/dify · error · PasswordMismatchError

password_mismatch

password_mismatch

Error message

The passwords do not match.

What it means

Raised by PasswordMismatchError in ForgotPasswordResetApi.post before any token lookup. The payload's new_password and password_confirm are compared directly; mismatch aborts the reset. Mirrors error 405 but for the password-reset completion step.

Source

Thrown at api/controllers/console/auth/forgot_password.py:164

@console_ns.route("/forgot-password/resets")
class ForgotPasswordResetApi(Resource):
    @console_ns.doc("reset_password")
    @console_ns.doc(description="Reset password with verification token")
    @console_ns.expect(console_ns.models[ForgotPasswordResetPayload.__name__])
    @console_ns.response(
        200,
        "Password reset successfully",
        console_ns.models[ForgotPasswordResetResponse.__name__],
    )
    @console_ns.response(400, "Invalid token or password mismatch")
    @setup_required
    @email_password_login_enabled
    @model_validate(ForgotPasswordResetPayload)
    def post(self, req_data: ForgotPasswordResetPayload):

        # Validate passwords match
        if req_data.new_password != req_data.password_confirm:
            raise PasswordMismatchError()

        # Validate token and get reset data
        reset_data = AccountService.get_reset_password_data(req_data.token)
        if not reset_data:
            raise InvalidTokenError()
        # Must use token in reset phase
        if reset_data.get("phase", "") != "reset":
            raise InvalidTokenError()

        # Revoke token to prevent reuse
        AccountService.revoke_reset_password_token(req_data.token)

        # Generate secure salt and hash password
        salt = secrets.token_bytes(16)
        password_hashed = hash_password(req_data.new_password, salt)

        email = reset_data.get("email", "")
        account = AccountService.get_account_by_email_with_case_fallback(email, session=db.session())

View on GitHub (pinned to ef8544b173)

Solutions

  1. Compare the two fields in the UI and disable submit until they match.
  2. Show a live mismatch indicator under the confirm field.
  3. Clear both fields and re-enter rather than patching.
  4. Send both fields from the same source value, not two independent inputs.

Example fix

// before
<button disabled={!newPassword}>Reset</button>
// after
disabled={newPassword !== passwordConfirm || !newPassword}
Defensive patterns

Strategy: validation

Validate before calling

if (newPassword !== passwordConfirm) {
  setFieldError('password_confirm', 'Passwords do not match');
  return;
}

Type guard

function passwordsMatch(a, b) { return typeof a === 'string' && a === b && a.length > 0; }

Prevention

When it happens

Trigger: POST /console/api/forgot-password/reset with new_password != password_confirm. Pure validation guard that runs first, before the token is examined.

Common situations: Password manager fills one field only; caps-lock; different keyboard layout; user types different values in the two boxes; frontend omits its own equality check.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/7174e64ae51d5b5a. Report an issue: GitHub.