infiniflow/ragflow · error · AuthException

Login failed: invalid JSON response ({exc})

Error message

Login failed: invalid JSON response ({exc})

What it means

Raised by login_user when response.json() fails on the login response (POST /admin/login or /auth/login). The auth endpoint returned a non-JSON body — typically an HTML error page from a gateway, a plain-text 502/504, or an empty body — so the client cannot extract code/message. The original parse exception is chained.

Source

Thrown at admin/client/user.py:70

    if res.get("code") == 0:
        return
    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. curl -i the login endpoint directly to see the raw non-JSON body and its status
  2. Verify the server is up and the API base URL/port in the client config is correct
  3. If a proxy is involved, check its error page configuration and upstream health
  4. Wait for services to be healthy before running the admin client (e.g. depends_on/healthcheck in compose)
Defensive patterns

Strategy: validation

Validate before calling

import json

def is_json_login_response(text: str) -> bool:
    try:
        parsed = json.loads(text)
    except ValueError:
        return False
    return isinstance(parsed, dict) and "code" in parsed

# probe the endpoint before the full flow:
resp = client.request("GET", "/")
if resp.headers.get("content-type", "").startswith("text/html"):
    raise RuntimeError("API base URL returns HTML — check server/proxy config")

Type guard

def is_json_body(response) -> bool:
    content_type = response.headers.get("content-type", "")
    return "application/json" in content_type

Try / catch

try:
    res = response.json()
except Exception as exc:
    raise AuthException(
        f"Login failed: non-JSON response (status={response.status_code}, "
        f"content-type={response.headers.get('content-type', 'unknown')})"
    ) from exc

Prevention

When it happens

Trigger: The login POST hits a reverse proxy returning an HTML 502/504 page; the server crashed mid-request returning an empty body; the URL points to a static site or wrong port; a redirect (302 to a login HTML page) followed by axios/requests returning HTML.

Common situations: Docker compose services not fully up when the admin script runs; nginx misrouting /auth/login; wrong port in the client's base URL; TLS termination returning an error page.

Understand the failure class

Related errors


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