{"record":{"id":"7d22031537e7f9dc","repo":"BerriAI/litellm","slug":"missing-jwt-public-key-url-from-environment","errorCode":null,"errorMessage":"Missing JWT Public Key URL from environment.","messagePattern":"Missing JWT Public Key URL from environment\\.","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"critical","filePath":"litellm/proxy/auth/handle_jwt.py","lineNumber":686,"sourceCode":"            await self.user_api_key_cache.async_set_cache(\n                key=cache_key,\n                value=keys,\n                ttl=self._get_public_key_cache_ttl(),\n            )\n        else:\n            keys = cached_keys\n\n        public_key: Final = self.parse_keys(keys=keys, kid=kid)\n        if public_key is not None:\n            return cast(dict, public_key)\n\n        raise NoMatchingJWTPublicKeyError(f\"No matching public key found. keys={resolved_jwks_url}, kid={kid}\")\n\n    async def get_public_key(self, kid: str | None) -> dict:\n        keys_url: Final = os.getenv(\"JWT_PUBLIC_KEY_URL\")\n\n        if keys_url is None:\n            raise Exception(\"Missing JWT Public Key URL from environment.\")\n\n        keys_url_list: Final = [url.strip() for url in keys_url.split(\",\") if url.strip()]\n\n        for key_url in keys_url_list:\n            try:\n                return await self._get_public_key_from_jwks_url(jwks_url=key_url, kid=kid)\n            except NoMatchingJWTPublicKeyError as e:\n                verbose_proxy_logger.debug(\"JWT Auth: No matching public key found at %s: %s\", key_url, e)\n\n        raise NoMatchingJWTPublicKeyError(f\"No matching public key found. keys={keys_url_list}, kid={kid}\")\n\n    def parse_keys(self, keys: JWKKeyValue, kid: str | None) -> JWTKeyItem | None:\n        public_key: JWTKeyItem | None = None\n        if len(keys) == 1:\n            if isinstance(keys, dict) and (keys.get(\"kid\", None) == kid or kid is None):\n                public_key = keys\n            elif isinstance(keys, list) and (keys[0].get(\"kid\", None) == kid or kid is None):\n                public_key = keys[0]","sourceCodeStart":668,"sourceCodeEnd":704,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/proxy/auth/handle_jwt.py#L668-L704","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before: container started without the variable\ndocker run litellm/litellm --config /config.yaml\n\n# after: pass the JWKS URL\ndocker run -e JWT_PUBLIC_KEY_URL=https://idp.example.com/protocol/openid-connect/certs litellm/litellm --config /config.yaml","handlingStrategy":"validation","validationCode":"import os, sys\n\nrequired = \"JWT_PUBLIC_KEY_URL\"\nif not os.getenv(required):\n    sys.exit(f\"missing required env var {required} for JWT auth - set it to your JWKS/discovery URL\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["jwt","environment-variables","configuration","authentication","startup"],"backgroundTag":"missing-env-var","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}