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
- Compare the two fields in the UI and disable submit until they match.
- Show a live mismatch indicator under the confirm field.
- Clear both fields and re-enter rather than patching.
- 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
- Disable submit until both fields are non-empty and equal.
- Show a real-time match indicator.
- Send both fields from the same state value.
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.