{"record":{"id":"e8acce5e5dbd0c48","repo":"langgenius/dify","slug":"email-register-limit","errorCode":"email_register_limit","errorMessage":"Too many failed email register attempts. Please try again in 24 hours.","messagePattern":"Too many failed email register attempts\\. Please try again in 24 hours\\.","errorType":"error_code","errorClass":"EmailRegisterLimitError","httpStatus":429,"severity":"warning","filePath":"api/controllers/console/auth/email_register.py","lineNumber":126,"sourceCode":"        token = AccountService.send_email_register_email(email=normalized_email, account=account, language=language)\n        return {\"result\": \"success\", \"data\": token}\n\n\n@console_ns.route(\"/email-register/validity\")\nclass EmailRegisterCheckApi(Resource):\n    @setup_required\n    @email_password_login_enabled\n    @email_register_enabled\n    @console_ns.expect(console_ns.models[EmailRegisterValidityPayload.__name__])\n    @console_ns.response(200, \"Success\", console_ns.models[VerificationTokenResponse.__name__])\n    @model_validate(EmailRegisterValidityPayload)\n    def post(self, req_data: EmailRegisterValidityPayload):\n\n        user_email = req_data.email.lower()\n\n        is_email_register_error_rate_limit = AccountService.is_email_register_error_rate_limit(user_email)\n        if is_email_register_error_rate_limit:\n            raise EmailRegisterLimitError()\n\n        token_data = AccountService.get_email_register_data(req_data.token)\n        if token_data is None:\n            raise InvalidTokenError()\n\n        token_email = token_data.get(\"email\")\n        normalized_token_email = token_email.lower() if isinstance(token_email, str) else token_email\n\n        if user_email != normalized_token_email:\n            raise InvalidEmailError()\n\n        if req_data.code != token_data.get(\"code\"):\n            AccountService.add_email_register_error_rate_limit(user_email)\n            raise EmailCodeError()\n\n        # Verified, revoke the first token\n        AccountService.revoke_email_register_token(req_data.token)\n","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/auth/email_register.py#L108-L144","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Stop retrying and wait 24 hours for the limit to expire, or have a privileged flow reset_email_register_error_rate_limit(email).","Request a fresh registration email and enter the code carefully on the first attempt.","If writing tests, mock AccountService.is_email_register_error_rate_limit to return false, or use a unique email per test.","Surface the 'email_register_limit' code to the user as a cooldown message, not a hard failure."],"exampleFix":"// before\nconst res = await checkValidity({ email, token, code });\n// after: respect the cooldown\nif (res.status === 400 && body.code === 'email_register_limit') {\n  showCooldownUntil(tomorrow());\n  return;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await checkValidity({ email, token, code });\n} catch (e) {\n  if (e.code === 'email_register_limit') showCooldown(24 * 3600);\n  else if (e.code === 'email_code_error') bumpAttemptCounter();\n  else throw e;\n}","preventionTips":["Show a live attempt counter so the user knows how close they are to the limit.","Throttle code-entry retries client-side (e.g., exponential backoff after each failure).","Mock is_email_register_error_rate_limit in tests to avoid accidental lockouts."],"tags":["auth","registration","rate-limit","brute-force-protection"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}