infiniflow/ragflow · error · AuthException

Login failed: {res.get('message')}

Error message

Login failed: {res.get('message')}

What it means

Raised by login_user when the login endpoint returned valid JSON but with code != 0 — the server explicitly rejected the login. The server's message is embedded (e.g. wrong email/password, account locked, captcha required). This is the standard credential-authentication failure path for both admin (/admin/login) and user (/auth/login) server types.

Source

Thrown at admin/client/user.py:72

    msg = res.get("message", "")
    if "has already registered" in msg:
        return
    raise AuthException(f"Register failed: {msg}")


def login_user(client: HttpClient, server_type: str, email: str, password: str) -> str:
    password_enc = encrypt_password(password)
    payload = {"email": email, "password": password_enc}
    if server_type == "admin":
        response = client.request("POST", "/admin/login", use_api_base=True, auth_kind=None, json_body=payload)
    else:
        response = client.request("POST", "/auth/login", use_api_base=True, auth_kind=None, json_body=payload)
    try:
        res = response.json()
    except Exception as exc:
        raise AuthException(f"Login failed: invalid JSON response ({exc})") from exc
    if res.get("code") != 0:
        raise AuthException(f"Login failed: {res.get('message')}")
    token = response.headers.get("Authorization")
    if not token:
        raise AuthException("Login failed: missing Authorization header")
    return token

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Read the embedded server message — it distinguishes wrong password vs. nonexistent user vs. locked account
  2. Verify encrypt_password matches the server's expected encoding (same base64/MD5 scheme and salt)
  3. Confirm using the right server_type/endpoint: 'admin' goes to /admin/login, otherwise /auth/login
  4. If the user was just registered, confirm registration succeeded (error 57 would have fired otherwise)
Defensive patterns

Strategy: try-catch

Validate before calling

# verify the password encoding matches what the server expects before login
from admin.client.user import encrypt_password

assert encrypt_password("test-password") != "", "encrypt_password produced empty output"
assert "@" in email, "email looks malformed"

Type guard

def is_rejected_login(res: dict) -> bool:
    """Server returned JSON envelope with a rejection code."""
    return isinstance(res, dict) and res.get("code") != 0

Try / catch

try:
    token = login_user(client, server_type, email, password)
except AuthException as e:
    msg = str(e)
    if "password" in msg.lower() or "email" in msg.lower():
        # credential problem — do not retry with the same values
        raise SystemExit(f"Check credentials: {msg}")
    if "locked" in msg.lower() or "disabled" in msg.lower():
        raise SystemExit(f"Account issue: {msg}")
    raise

Prevention

When it happens

Trigger: POST email+encrypted password to /admin/login or /auth/login where the account does not exist, the password is wrong (note passwords are passed through encrypt_password — a mismatched encoding scheme also produces 'wrong password'), or the account is disabled/locked.

Common situations: Password encrypted differently than the server expects (encryption scheme drift between client and server versions); account registered with a different email; admin login attempted against a user-only endpoint or vice versa; account deactivated.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/d3ae263a685972dc. Report an issue: GitHub.