langgenius/dify · warning · EmailPasswordResetLimitError
email_password_reset_limit
email_password_reset_limit
Error message
Too many failed password reset attempts. Please try again in 24 hours.
What it means
Raised by EmailPasswordResetLimitError in ForgotPasswordCheckApi.post when AccountService.is_forgot_password_error_rate_limit(user_email) returns true. Like the register counterpart, this accumulates failed code-verifications per email and locks the email out of the reset flow for 24 hours once the threshold is crossed.
Source
Thrown at api/controllers/console/auth/forgot_password.py:116
@console_ns.doc("check_forgot_password_code")
@console_ns.doc(description="Verify password reset code")
@console_ns.expect(console_ns.models[ForgotPasswordCheckPayload.__name__])
@console_ns.response(
200,
"Code verified successfully",
console_ns.models[ForgotPasswordCheckResponse.__name__],
)
@console_ns.response(400, "Invalid code or token")
@setup_required
@email_password_login_enabled
@model_validate(ForgotPasswordCheckPayload)
def post(self, req_data: ForgotPasswordCheckPayload):
user_email = req_data.email.lower()
is_forgot_password_error_rate_limit = AccountService.is_forgot_password_error_rate_limit(user_email)
if is_forgot_password_error_rate_limit:
raise EmailPasswordResetLimitError()
token_data = AccountService.get_reset_password_data(req_data.token)
if token_data is None:
raise InvalidTokenError()
token_email = token_data.get("email")
if not isinstance(token_email, str):
raise InvalidEmailError()
normalized_token_email = token_email.lower()
if user_email != normalized_token_email:
raise InvalidEmailError()
if req_data.code != token_data.get("code"):
AccountService.add_forgot_password_error_rate_limit(user_email)
raise EmailCodeError()
# Verified, revoke the first tokenView on GitHub (pinned to ef8544b173)
Solutions
- Wait 24 hours for the per-email lockout to expire, or have a privileged flow call reset_forgot_password_error_rate_limit(email).
- Request a fresh reset email and enter the code carefully on the first try.
- In tests, mock is_forgot_password_error_rate_limit to false or use unique emails per case.
- Surface 'email_password_reset_limit' as a cooldown message in the UI.
Example fix
// before
const res = await checkValidity({ email, token, code });
// after
if (res.code === 'email_password_reset_limit') showResetCooldown(); Defensive patterns
Strategy: try-catch
Try / catch
try {
await checkValidity({ email, token, code });
} catch (e) {
if (e.code === 'email_password_reset_limit') showResetCooldown(24 * 3600);
else if (e.code === 'email_code_error') bumpAttempts();
else throw e;
} Prevention
- Show an attempt counter for the reset code entry.
- Throttle retries client-side after each failure.
- Mock is_forgot_password_error_rate_limit in tests.
When it happens
Trigger: POST /console/api/forgot-password/validity with an email that has too many prior failed reset-code verifications. Evaluated before the token is looked up.
Common situations: User repeatedly enters wrong reset codes; brute-force attempt on the reset code; tests hammering the validity endpoint with a fixed email; a previous session's failed attempts still counting against the email.
Related errors
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/583e551f83e8e2a6.
Report an issue: GitHub.