BerriAI/litellm · critical · Exception
Missing JWT Public Key URL from environment.
Error message
Missing JWT Public Key URL from environment.
What it means
Raised at the top of get_public_key in litellm/proxy/auth/handle_jwt.py: the JWT authentication path was invoked (a bearer JWT arrived and JWT auth is enabled) but the JWT_PUBLIC_KEY_URL environment variable is not set, so there is nowhere to fetch verification keys from. Every JWT-authenticated request fails until it is configured.
Source
Thrown at litellm/proxy/auth/handle_jwt.py:686
await self.user_api_key_cache.async_set_cache(
key=cache_key,
value=keys,
ttl=self._get_public_key_cache_ttl(),
)
else:
keys = cached_keys
public_key: Final = self.parse_keys(keys=keys, kid=kid)
if public_key is not None:
return cast(dict, public_key)
raise NoMatchingJWTPublicKeyError(f"No matching public key found. keys={resolved_jwks_url}, kid={kid}")
async def get_public_key(self, kid: str | None) -> dict:
keys_url: Final = os.getenv("JWT_PUBLIC_KEY_URL")
if keys_url is None:
raise Exception("Missing JWT Public Key URL from environment.")
keys_url_list: Final = [url.strip() for url in keys_url.split(",") if url.strip()]
for key_url in keys_url_list:
try:
return await self._get_public_key_from_jwks_url(jwks_url=key_url, kid=kid)
except NoMatchingJWTPublicKeyError as e:
verbose_proxy_logger.debug("JWT Auth: No matching public key found at %s: %s", key_url, e)
raise NoMatchingJWTPublicKeyError(f"No matching public key found. keys={keys_url_list}, kid={kid}")
def parse_keys(self, keys: JWKKeyValue, kid: str | None) -> JWTKeyItem | None:
public_key: JWTKeyItem | None = None
if len(keys) == 1:
if isinstance(keys, dict) and (keys.get("kid", None) == kid or kid is None):
public_key = keys
elif isinstance(keys, list) and (keys[0].get("kid", None) == kid or kid is None):
public_key = keys[0]View on GitHub (pinned to 77b7c6c40c)
Solutions
- Set JWT_PUBLIC_KEY_URL in the proxy's environment to your JWKS or OIDC discovery URL
- Alternatively configure the public key statically in the config YAML under litellm_settings.litellm_jwtauth (JWT_PUBLIC_KEY / public key fields) so the env lookup path is not needed
- Verify with a printout at startup (e.g. echo in the entrypoint) that the variable is actually exported in the container running the proxy
Example fix
# before: container started without the variable docker run litellm/litellm --config /config.yaml # after: pass the JWKS URL docker run -e JWT_PUBLIC_KEY_URL=https://idp.example.com/protocol/openid-connect/certs litellm/litellm --config /config.yaml
Defensive patterns
Strategy: validation
Validate before calling
import os, sys
required = "JWT_PUBLIC_KEY_URL"
if not os.getenv(required):
sys.exit(f"missing required env var {required} for JWT auth - set it to your JWKS/discovery URL") Prevention
- Assert required JWT env vars in the container entrypoint before the proxy starts
- Keep env definitions in versioned deployment manifests/secrets, not shell sessions
- Prefer the config-yaml litellm_jwtauth block so key URLs live with the rest of the config
When it happens
Trigger: Client sends Authorization: Bearer <jwt> to a proxy configured for JWT auth, but the deployment never set JWT_PUBLIC_KEY_URL (env var or its config equivalent), so get_public_key raises immediately.
Common situations: Docker/Kubernetes deployment where the env var is missing from the manifest or secret; config migrated from static JWT_PUBLIC_KEY to JWKS-based auth without adding the URL; CI/local environment diverging from prod env setup.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Either 'REDIS_URL' or both 'REDIS_HOST' and 'REDIS_PORT' mus
- LEVOAI_ORG_ID environment variable is required for Levo inte
- LEVOAI_WORKSPACE_ID environment variable is required for Lev
- Missing keys={missing_keys} in environment.
- OIDC UserInfo endpoint not configured. Set 'oidc_userinfo_en
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/7d22031537e7f9dc.
Report an issue: GitHub.