{"record":{"id":"532fcc14481f5efc","repo":"infiniflow/ragflow","slug":"failed-to-fetch-user-info-e","errorCode":null,"errorMessage":"Failed to fetch user info: {e}","messagePattern":"Failed to fetch user info: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"api/apps/auth/oauth.py","lineNumber":116,"sourceCode":"                timeout=self.http_request_timeout,\n            )\n            response.raise_for_status()\n            return response.json()\n        except Exception as e:\n            raise ValueError(f\"Failed to exchange authorization code for token: {e}\")\n\n    def fetch_user_info(self, access_token, **kwargs):\n        \"\"\"\n        Fetch user information using access token.\n        \"\"\"\n        try:\n            headers = {\"Authorization\": f\"Bearer {access_token}\"}\n            response = sync_request(\"GET\", self.userinfo_url, headers=headers, timeout=self.http_request_timeout)\n            response.raise_for_status()\n            user_info = response.json()\n            return self.normalize_user_info(user_info)\n        except Exception as e:\n            raise ValueError(f\"Failed to fetch user info: {e}\")\n\n    async def async_fetch_user_info(self, access_token, **kwargs):\n        \"\"\"Async variant of fetch_user_info using httpx.\"\"\"\n        headers = {\"Authorization\": f\"Bearer {access_token}\"}\n        try:\n            response = await async_request(\n                \"GET\",\n                self.userinfo_url,\n                headers=headers,\n                timeout=self.http_request_timeout,\n            )\n            response.raise_for_status()\n            user_info = response.json()\n            return self.normalize_user_info(user_info)\n        except Exception as e:\n            raise ValueError(f\"Failed to fetch user info: {e}\")\n\n    def normalize_user_info(self, user_info):","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/api/apps/auth/oauth.py#L98-L134","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# verify endpoint + token\ncurl -H 'Authorization: Bearer $ACCESS_TOKEN' https://provider.example/userinfo\n# expect JSON with email/username fields","handlingStrategy":"try-catch","validationCode":"def userinfo_precheck(cfg, token):\n    assert cfg.get(\"userinfo_url\"), \"userinfo_url missing in oauth2 config\"\n    import requests\n    r = requests.get(cfg[\"userinfo_url\"], headers={\"Authorization\": f\"Bearer {token}\"}, timeout=10)\n    assert r.ok and isinstance(r.json(), dict), f\"userinfo probe failed: {r.status_code}\"","typeGuard":null,"tryCatchPattern":"try:\n    info = client.fetch_user_info(access_token)\nexcept ValueError as e:\n    if \"401\" in str(e):\n        # token unusable - do not retry with the same token\n        raise SessionExpired(\"re-authentication required\")\n    raise","preventionTips":["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."],"tags":["auth","oauth","userinfo","http","configuration"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}