langgenius/dify · error · AuthenticationFailedError
authentication_failed
authentication_failed
Error message
Invalid email or password.
What it means
Raised in POST /console/api/login (HTTP 401, code authentication_failed) when _authenticate_account_with_case_fallback raises services.errors.account.AccountPasswordError for both the original and lowercased email. The controller increments the login error rate-limit counter and re-raises as AuthenticationFailedError. Deliberately returns 401 (not 404) to avoid leaking which emails exist.
Source
Thrown at api/controllers/console/auth/login.py:165
data = invitation_data.get("data", {})
invitee_email = data.get("email") if data else None
invitee_email_normalized = invitee_email.lower() if isinstance(invitee_email, str) else invitee_email
if invitee_email_normalized != normalized_email:
_log_console_login_failure(
email=normalized_email,
reason=LoginFailureReason.INVALID_INVITATION_EMAIL,
)
raise InvalidEmailError()
account = _authenticate_account_with_case_fallback(
request_email, normalized_email, req_data.password, invite_token
)
except services.errors.account.AccountLoginError:
_log_console_login_failure(email=normalized_email, reason=LoginFailureReason.ACCOUNT_BANNED)
raise AccountBannedError()
except services.errors.account.AccountPasswordError as exc:
AccountService.add_login_error_rate_limit(normalized_email)
_log_console_login_failure(email=normalized_email, reason=LoginFailureReason.INVALID_CREDENTIALS)
raise AuthenticationFailedError() from exc
tenants = TenantService.get_join_tenants(account, session=db.session())
if len(tenants) == 0:
if (
FeatureService.is_workspace_creation_allowed()
and not FeatureService.get_license().workspaces.is_available()
):
raise WorkspacesLimitExceeded()
else:
return SimpleResultOptionalDataResponse(
result="fail",
data="workspace not found, please contact system admin to invite you to join in a workspace",
).model_dump(mode="json")
token_pair = AccountService.login(account=account, session=db.session(), ip_address=extract_remote_ip(request))
AccountService.reset_login_error_rate_limit(normalized_email)
# Create response with cookies instead of returning tokens in body
# response-contract:ignore cookie-bearing Flask responseView on GitHub (pinned to ef8544b173)
Solutions
- Use the forgot-password flow to reset the password.
- Confirm the email is correct and the account exists in this environment.
- Verify the client is encrypting the password the same way the server's @decrypt_password_field expects (check the public key / RSA setup).
- After 5 failures the account hits error 422 lockout; stop retrying and reset the password.
Example fix
// before
fetch('/console/api/login', {body: JSON.stringify({email, password: plaintext})})
// after - ensure password is encrypted with the server's public key first
const encrypted = await encryptWithPublicKey(serverPublicKey, plaintext)
fetch('/console/api/login', {body: JSON.stringify({email, password: encrypted})}) Defensive patterns
Strategy: try-catch
Validate before calling
# Sanity-check the encrypted password payload length before sending
encrypted = encrypt_for_server(plaintext_password)
if len(encrypted) < EXPECTED_MIN_LEN:
abort('Password encryption failed; refresh the page.')
submit_login(email, encrypted) Type guard
null
Try / catch
from controllers.console.auth.error import AuthenticationFailedError
attempts = 0
while attempts < 3:
try:
return do_login()
except AuthenticationFailedError:
attempts += 1
offer_password_reset() Prevention
- Confirm the client uses the server's current RSA public key for the password field.
- Rate-limit retries client-side and offer password reset early.
- Verify the user is on the correct environment URL.
When it happens
Trigger: POST /console/api/login with a wrong password (or a non-existent email) after both case variants of the email have been tried by _authenticate_account_with_case_fallback. Each failure increments login_error_rate_limit:<email>.
Common situations: User mistyped the password; password was recently changed; user is on the wrong environment (e.g., staging creds in prod); account email is wrong or non-existent; client did not apply the same encryption the @decrypt_password_field decorator expects.
Related errors
AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12).
Data as JSON: /api/errors/5b1a5dcedf8200bd.
Report an issue: GitHub.