infiniflow/ragflow · error · ValueError

Failed to fetch github user info: {e}

Error message

Failed to fetch github user info: {e}

What it means

GithubOAuthClient.fetch_user_info calls GET /user and GET /user/emails with the access token and wraps any failure in ValueError('Failed to fetch github user info: {e}') (api/apps/auth/github.py:52). The except is broad: it fires on HTTP errors (401 bad token, 403 scope missing), network/timeouts, JSON decode errors, and a subtle TypeError when the user has no 'primary' email - next(...) returns None and ['email'] raises inside the try.

Source

Thrown at api/apps/auth/github.py:52

        super().__init__(config)

    def fetch_user_info(self, access_token, **kwargs):
        """
        Fetch GitHub user info (synchronous).
        """
        user_info = {}
        try:
            headers = {"Authorization": f"Bearer {access_token}"}
            response = sync_request("GET", self.userinfo_url, headers=headers, timeout=self.http_request_timeout)
            response.raise_for_status()
            user_info.update(response.json())
            email_response = sync_request("GET", self.userinfo_url + "/emails", headers=headers, timeout=self.http_request_timeout)
            email_response.raise_for_status()
            email_info = email_response.json()
            user_info["email"] = next((email for email in email_info if email["primary"]), None)["email"]
            return self.normalize_user_info(user_info)
        except Exception as e:
            raise ValueError(f"Failed to fetch github user info: {e}")

    async def async_fetch_user_info(self, access_token, **kwargs):
        """Async variant of fetch_user_info using httpx."""
        user_info = {}
        headers = {"Authorization": f"Bearer {access_token}"}
        try:
            response = await async_request(
                "GET",
                self.userinfo_url,
                headers=headers,
                timeout=self.http_request_timeout,
            )
            response.raise_for_status()
            user_info.update(response.json())

            email_response = await async_request(
                "GET",
                self.userinfo_url + "/emails",

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Ensure the GitHub OAuth app requests the 'user:email' scope and re-authorize so the token carries it.
  2. Test the token directly: curl -H 'Authorization: Bearer <token>' https://api.github.com/user/emails must return a list containing an entry with "primary": true.
  3. For GitHub Enterprise, verify github_api_base/host config so userinfo_url resolves to <host>/api/v3/user.
  4. Handle users with no primary email (corporate SAML-only accounts) by falling back to login-based identity or requiring an email.

Example fix

# verify token + scope
curl -H 'Authorization: Bearer $TOKEN' https://api.github.com/user/emails
# expect: [{"email": "...", "primary": true, ...}]
Defensive patterns

Strategy: try-catch

Validate before calling

import requests

def github_token_ok(token, base="https://api.github.com"):
    h = {"Authorization": f"Bearer {token}"}
    u = requests.get(f"{base}/user", headers=h, timeout=10)
    e = requests.get(f"{base}/user/emails", headers=h, timeout=10)
    emails = e.json() if e.ok else []
    return u.ok and e.ok and any(x.get("primary") for x in emails)

Try / catch

try:
    info = client.fetch_user_info(access_token)
except ValueError as e:
    msg = str(e)
    if "401" in msg:
        restart_oauth_flow()          # token expired - re-authenticate
    elif "NoneType" in msg or "primary" in msg:
        raise UserVisibleError("Your GitHub account has no primary email; add one and retry")
    else:
        retry_or_alert(msg)

Prevention

When it happens

Trigger: Access token expired or revoked (401 on /user); token lacks the 'user:email' scope so /user/emails returns [] or 403; GitHub Enterprise userinfo_url misconfigured (wrong github_api_base); user has no primary/verified email on file; transient network failure or timeout.

Common situations: OAuth app created without requesting user:email scope; self-hosted GitHub Enterprise with an API base URL missing /api/v3; users with private emails and empty email list; long-running sessions with expired tokens.

Related errors


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