BerriAI/litellm · error · Exception
Failed to fetch OIDC UserInfo: {e}
Error message
Failed to fetch OIDC UserInfo: {e} What it means
Catch-all raised in get_userinfo: any exception during the UserInfo exchange that is not the explicit non-200 branch (network errors, DNS failures, TLS problems, timeouts, or unexpected parse/encoding errors) is logged ('Error fetching OIDC UserInfo: ...') and re-raised wrapped as 'Failed to fetch OIDC UserInfo: <cause>'. The chained cause text identifies the underlying failure.
Source
Thrown at litellm/proxy/auth/handle_jwt.py:783
if response.status_code != 200:
raise Exception(f"OIDC UserInfo endpoint returned status {response.status_code}: {response.text}")
userinfo: Final = response.json()
verbose_proxy_logger.debug("Received OIDC UserInfo: %s", userinfo)
# Cache the userinfo response
await self.user_api_key_cache.async_set_cache(
key=cache_key,
value=userinfo,
ttl=self.litellm_jwtauth.oidc_userinfo_cache_ttl,
)
return userinfo
except Exception as e:
verbose_proxy_logger.error("Error fetching OIDC UserInfo: %s", e)
raise Exception(f"Failed to fetch OIDC UserInfo: {e}")
_unscoped_jwt_warning_emitted = False
@classmethod
def _build_decode_kwargs(cls) -> dict:
"""Build the audience/issuer/options kwargs for ``jwt.decode``.
Setting ``JWT_AUDIENCE`` (and optionally ``JWT_ISSUER``) turns on the
corresponding PyJWT verifications, blocking cross-tenant tokens
minted by other applications that share the same IdP signing keys.
When both are unset PyJWT only checks the signature and expiry, which
is preserved for backward compatibility but logged once as a warning.
The warning fires even in mixed deployments that also configure
``LiteLLM_JWTAuth.issuers``: tokens whose ``iss`` does not match any
configured issuer fall through to this global path, and if env-var
scoping is absent that fallback is itself unscoped.
"""View on GitHub (pinned to 77b7c6c40c)
Solutions
- Read the wrapped cause in the message - it distinguishes DNS vs connection vs SSL vs timeout
- From the proxy container, curl the UserInfo endpoint to verify network paths, DNS, and TLS trust
- Allowlist the IdP domain in egress rules / NetworkPolicies and add the IdP CA to the container trust store if using a private CA
- For slow IdPs, raise the HTTP client timeout used for UserInfo fetches
Defensive patterns
Strategy: retry
Validate before calling
import httpx, socket
def userinfo_endpoint_reachable(url: str) -> bool:
host = httpx.URL(url).host
try:
socket.getaddrinfo(host, 443)
return True
except socket.gaierror:
return False Try / catch
import asyncio
async def fetch_userinfo_with_retry(fetch, attempts=3):
for i in range(attempts):
try:
return await fetch()
except Exception as e:
if "Failed to fetch OIDC UserInfo" in str(e) and i < attempts - 1:
await asyncio.sleep(2 ** i) # transient network/DNS/TLS - back off
continue
raise Prevention
- Verify egress from the proxy pod to the IdP host (DNS, firewall, NetworkPolicy) before enabling UserInfo
- Trust the IdP's CA in the proxy container when using a private CA
- Distinguish transient causes by the wrapped text (DNS/connection/SSL/timeout) before retrying
When it happens
Trigger: The proxy cannot reach oidc_userinfo_endpoint at all - DNS resolution failure, connection refused, TLS handshake error, or HTTP client timeout - while handling a JWT-authenticated request that requires UserInfo claims.
Common situations: Egress firewall or NetworkPolicy blocking the IdP host from the proxy pod; wrong DNS/internal hostname for the IdP inside Kubernetes; self-signed cert on the IdP failing verification; IdP slow enough to hit the client timeout.
Related errors
- Error fetching file '{file_path}': {e}
- OIDC UserInfo endpoint not configured. Set 'oidc_userinfo_en
- OIDC UserInfo endpoint returned status {response.status_code
- Cisco AI Defense {surface} API request failed: {exc}
- Failed to fetch AgentOps token: {response.text}
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/4d20b4aaa863d794.
Report an issue: GitHub.