{"record":{"id":"2090db8bdab652cc","repo":"crewAIInc/crewAI","slug":"unable-to-fetch-signing-keys","errorCode":null,"errorMessage":"Unable to fetch signing keys","messagePattern":"Unable to fetch signing keys","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"error","filePath":"lib/crewai/src/crewai/a2a/auth/server_schemes.py","lineNumber":346,"sourceCode":"        except jwt.MissingRequiredClaimError as e:\n            logger.debug(\n                \"OIDC authentication failed\",\n                extra={\"reason\": \"missing_claim\", \"claim\": e.claim, \"scheme\": \"oidc\"},\n            )\n            raise HTTPException(\n                status_code=HTTP_401_UNAUTHORIZED,\n                detail=f\"Missing required claim: {e.claim}\",\n            ) from None\n        except jwt.PyJWKClientError as e:\n            logger.error(\n                \"OIDC authentication failed\",\n                extra={\n                    \"reason\": \"jwks_client_error\",\n                    \"error\": str(e),\n                    \"scheme\": \"oidc\",\n                },\n            )\n            raise HTTPException(\n                status_code=HTTP_503_SERVICE_UNAVAILABLE,\n                detail=\"Unable to fetch signing keys\",\n            ) from None\n        except jwt.InvalidTokenError as e:\n            logger.debug(\n                \"OIDC authentication failed\",\n                extra={\"reason\": \"invalid_token\", \"error\": str(e), \"scheme\": \"oidc\"},\n            )\n            raise HTTPException(\n                status_code=HTTP_401_UNAUTHORIZED,\n                detail=\"Invalid or missing authentication credentials\",\n            ) from None\n\n\nclass OAuth2ServerAuth(ServerAuthScheme):\n    \"\"\"OAuth2 authentication for A2A server.\n\n    Declares OAuth2 security scheme in AgentCard and validates tokens using","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai/src/crewai/a2a/auth/server_schemes.py#L328-L364","documentation":"Raised by OIDCAuth.authenticate() when the PyJWKClient cannot fetch or find signing keys (PyJWKClientError), e.g. the JWKS endpoint is unreachable, returns an error, or contains no key matching the token's kid. It maps to HTTP 503 Service Unavailable, signaling a transient upstream problem rather than an invalid credential, and logs the underlying error at ERROR level with reason='jwks_client_error'.","triggerScenarios":"jwks_url points to a host that is down, times out, or returns non-200; the IdP rotated keys and the cached JWKS lacks the token's kid while refetch fails; a firewall/DNS failure between the CrewAI server and the IdP; JWKS endpoint behind rate limiting returning 429.","commonSituations":"IdP outage or maintenance window; network egress restrictions from containers (no DNS/egress to the IdP domain); key rotation races; self-signed TLS on the JWKS endpoint breaking the fetch.","solutions":["Verify the JWKS URL from the server host: curl -v <jwks_url> and fix DNS/firewall/TLS issues.","Retry the request after a short delay — PyJWKClient caches keys, so a transient failure clears on the next fetch.","Ensure jwks_url matches the IdP's current jwks_uri from its discovery document (rotated endpoints).","For containerized deployments, confirm egress rules and CA trust so the JWKS fetch succeeds."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import httpx\n\nresp = httpx.get(jwks_url, timeout=5)\nassert resp.status_code == 200 and resp.json().get(\"keys\"), (\n    f\"JWKS endpoint unhealthy: {resp.status_code}\"\n)","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        return await scheme.authenticate(token)\n    except HTTPException as e:\n        if e.status_code == 503 and e.detail == \"Unable to fetch signing keys\":\n            await asyncio.sleep(2 ** attempt)  # transient upstream failure: back off and retry\n        else:\n            raise","preventionTips":["Health-check the JWKS endpoint as part of service readiness probes.","Ensure container egress/DNS/CA trust allows reaching the IdP.","Retry with backoff on 503 — JWKS failures are usually transient."],"tags":["a2a","oidc","jwks","network","retryable","http-503"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}