infiniflow/ragflow · error · ValueError
Failed to fetch user info: {e}
Error message
Failed to fetch user info: {e} What it means
Generic OAuthClient.fetch_user_info GETs userinfo_url with a Bearer access token, then calls normalize_user_info; any HTTP, transport, JSON, or normalization failure is re-raised as ValueError('Failed to fetch user info: {e}') (api/apps/auth/oauth.py:116). Used by the plain 'oauth2' client type, so endpoint and response-shape problems dominate.
Source
Thrown at api/apps/auth/oauth.py:116
timeout=self.http_request_timeout,
)
response.raise_for_status()
return response.json()
except Exception as e:
raise ValueError(f"Failed to exchange authorization code for token: {e}")
def fetch_user_info(self, access_token, **kwargs):
"""
Fetch user information using access token.
"""
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 = response.json()
return self.normalize_user_info(user_info)
except Exception as e:
raise ValueError(f"Failed to fetch user info: {e}")
async def async_fetch_user_info(self, access_token, **kwargs):
"""Async variant of fetch_user_info using httpx."""
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 = response.json()
return self.normalize_user_info(user_info)
except Exception as e:
raise ValueError(f"Failed to fetch user info: {e}")
def normalize_user_info(self, user_info):View on GitHub (pinned to 554fb1133a)
Solutions
- Curl userinfo_url with the Bearer token and confirm it returns JSON with an email and a username-compatible field.
- Correct userinfo_url in the provider configuration (for OIDC providers prefer type 'oidc' + issuer so discovery fills it in).
- Verify the token exchange succeeded immediately before this call - a failed exchange often surfaces here.
- Confirm the token's scopes include profile/email access.
Example fix
# verify endpoint + token curl -H 'Authorization: Bearer $ACCESS_TOKEN' https://provider.example/userinfo # expect JSON with email/username fields
Defensive patterns
Strategy: try-catch
Validate before calling
def userinfo_precheck(cfg, token):
assert cfg.get("userinfo_url"), "userinfo_url missing in oauth2 config"
import requests
r = requests.get(cfg["userinfo_url"], headers={"Authorization": f"Bearer {token}"}, timeout=10)
assert r.ok and isinstance(r.json(), dict), f"userinfo probe failed: {r.status_code}" Try / catch
try:
info = client.fetch_user_info(access_token)
except ValueError as e:
if "401" in str(e):
# token unusable - do not retry with the same token
raise SessionExpired("re-authentication required")
raise Prevention
- Prefer type 'oidc' with issuer so userinfo_url comes from discovery instead of hand-entry.
- Probe the userinfo endpoint once when configuring a new provider.
- Confirm the provider returns email claims; map custom field names in normalize_user_info if needed.
When it happens
Trigger: Access token invalid or expired (401); userinfo_url wrong or missing in the provider config; provider's userinfo response lacks the fields normalize_user_info expects; response is not JSON; network failure or timeout hitting userinfo_url.
Common situations: Hand-configured generic OAuth2 providers where the userinfo endpoint was guessed; field-name mismatches between providers (sub vs username, no email claim); tokens expiring between exchange and userinfo call.
Related errors
- Failed to exchange authorization code for token: {e}
- Unsupported type: {channel_type}
- Failed to fetch github user info: {e}
- 100
- Invalid channel name: {channel}
AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15).
Data as JSON: /api/errors/532fcc14481f5efc.
Report an issue: GitHub.