langgenius/dify · error · InvalidEmailError
invalid_email
invalid_email
Error message
The email address is not valid.
What it means
Raised by InvalidEmailError in ForgotPasswordCheckApi.post when token_data.get('email') is not a str instance. The reset token's payload is expected to carry an email string; a non-string (None, dict, list) indicates the token was tampered with, mis-issued, or stored in a legacy/corrupt format. Defensive type check before lowercasing.
Source
Thrown at api/controllers/console/auth/forgot_password.py:124
@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 token
AccountService.revoke_reset_password_token(req_data.token)
# Refresh token data by generating a new token
_, new_token = AccountService.generate_reset_password_token(
token_email, code=req_data.code, additional_data={"phase": "reset"}
)
AccountService.reset_forgot_password_error_rate_limit(user_email)View on GitHub (pinned to ef8544b173)
Solutions
- Restart the forgot-password flow to obtain a token known to carry a valid email claim.
- If reproducible across users, inspect the token-generation code path (generate_reset_password_token) for a missing email field.
- Check the token store backend for corruption or partial writes.
- Add server-side logging of the token payload shape when this fires to diagnose issuance bugs.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await checkValidity({ email, token, code });
} catch (e) {
if (e.code === 'invalid_email') await restartResetFlow(email); // likely corrupt token
else throw e;
} Prevention
- Treat a persistent invalid_email on a fresh token as a server-side issuance bug; file an issue with logs.
- Restart the reset flow to get a token with a valid email claim.
- Add server-side payload logging when this guard fires.
When it happens
Trigger: POST /console/api/forgot-password/validity with a token that resolves to data whose 'email' field is missing or not a string. Distinct from error 415 (email mismatch): this fires before any comparison.
Common situations: Token payload corrupted in the store; a manually crafted token that decodes but lacks the email claim; migration between token formats leaving legacy tokens without email; a bug in token generation omitting the email field.
Related errors
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/a603045d7104d811.
Report an issue: GitHub.