langgenius/dify · error · InvalidEmailError
invalid_email
invalid_email
Error message
The email address is not valid.
What it means
Raised by InvalidEmailError in EmailRegisterCheckApi.post when the lowercased email in the request body does not match the email bound to the registration token. The token was issued for one address; the client is now claiming a different one. This guards against token/email substitution mid-flow.
Source
Thrown at api/controllers/console/auth/email_register.py:136
@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)
# Refresh token data by generating a new token
_, new_token = AccountService.generate_email_register_token(
user_email, code=req_data.code, additional_data={"phase": "register"}
)
AccountService.reset_email_register_error_rate_limit(user_email)
return {"is_valid": True, "email": normalized_token_email, "token": new_token}
@console_ns.route("/email-register")View on GitHub (pinned to ef8544b173)
Solutions
- Use the exact email address that received the registration link, character-for-character.
- Pull email from the same client state that received the token, not from a re-typed input.
- Normalize both sides to lowercase before comparing client-side as a sanity check.
- If the wrong email was registered, restart email-send with the correct address.
Example fix
// before
checkValidity({ email: typedEmail, token, code });
// after: derive email from the token-issuing flow
checkValidity({ email: issuedToEmail.toLowerCase(), token, code }); Defensive patterns
Strategy: validation
Validate before calling
// Derive email from the same state that holds the token
const emailForCheck = issuedToEmail.toLowerCase();
if (emailForCheck !== userInputEmail.toLowerCase()) {
warnEmailMismatch();
return;
} Try / catch
try {
await checkValidity({ email: emailForCheck, token, code });
} catch (e) {
if (e.code === 'invalid_email') showEmailMismatchHint();
else throw e;
} Prevention
- Freeze the email field once the token is issued, or pre-fill it read-only.
- Lowercase both sides before comparing.
- Do not let the user retype the email at the verification step.
When it happens
Trigger: POST /console/api/email-register/validity where the token's stored email differs from req_data.email (after both are lowercased). Common when a user starts registration with one address and types another at verification, or when the client passes the wrong email field.
Common situations: Plus-addressing differences (user+test@x vs user@x), autocorrect changing the address between steps, shared browser where two users mix up tabs, or a frontend bug sending stale email state.
Related errors
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/fdfa514e8cbc02d3.
Report an issue: GitHub.