langgenius/dify · warning · EmailRegisterLimitError

email_register_limit

email_register_limit

Error message

Too many failed email register attempts. Please try again in 24 hours.

What it means

Raised by EmailRegisterLimitError in EmailRegisterCheckApi.post when AccountService.is_email_register_error_rate_limit returns true. The rate limiter accumulates failures from bad verification codes (see add_email_register_error_rate_limit) and blocks the email for 24 hours once the threshold is crossed. This protects the code-verification step from brute-forcing.

Source

Thrown at api/controllers/console/auth/email_register.py:126

        token = AccountService.send_email_register_email(email=normalized_email, account=account, language=language)
        return {"result": "success", "data": token}


@console_ns.route("/email-register/validity")
class EmailRegisterCheckApi(Resource):
    @setup_required
    @email_password_login_enabled
    @email_register_enabled
    @console_ns.expect(console_ns.models[EmailRegisterValidityPayload.__name__])
    @console_ns.response(200, "Success", console_ns.models[VerificationTokenResponse.__name__])
    @model_validate(EmailRegisterValidityPayload)
    def post(self, req_data: EmailRegisterValidityPayload):

        user_email = req_data.email.lower()

        is_email_register_error_rate_limit = AccountService.is_email_register_error_rate_limit(user_email)
        if is_email_register_error_rate_limit:
            raise EmailRegisterLimitError()

        token_data = AccountService.get_email_register_data(req_data.token)
        if token_data is None:
            raise InvalidTokenError()

        token_email = token_data.get("email")
        normalized_token_email = token_email.lower() if isinstance(token_email, str) else token_email

        if user_email != normalized_token_email:
            raise InvalidEmailError()

        if req_data.code != token_data.get("code"):
            AccountService.add_email_register_error_rate_limit(user_email)
            raise EmailCodeError()

        # Verified, revoke the first token
        AccountService.revoke_email_register_token(req_data.token)

View on GitHub (pinned to ef8544b173)

Solutions

  1. Stop retrying and wait 24 hours for the limit to expire, or have a privileged flow reset_email_register_error_rate_limit(email).
  2. Request a fresh registration email and enter the code carefully on the first attempt.
  3. If writing tests, mock AccountService.is_email_register_error_rate_limit to return false, or use a unique email per test.
  4. Surface the 'email_register_limit' code to the user as a cooldown message, not a hard failure.

Example fix

// before
const res = await checkValidity({ email, token, code });
// after: respect the cooldown
if (res.status === 400 && body.code === 'email_register_limit') {
  showCooldownUntil(tomorrow());
  return;
}
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await checkValidity({ email, token, code });
} catch (e) {
  if (e.code === 'email_register_limit') showCooldown(24 * 3600);
  else if (e.code === 'email_code_error') bumpAttemptCounter();
  else throw e;
}

Prevention

When it happens

Trigger: POST /console/api/email-register/validity with an email that has produced too many failed code validations within the rate-limit window. Triggered before the token is even examined.

Common situations: User mistypes the email verification code repeatedly; automated tests hammering the validity endpoint; a script trying to guess codes. Resets only via reset_email_register_error_rate_limit after a successful validation.

Related errors


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