{"record":{"id":"86f1fbc90ed8e363","repo":"crewAIInc/crewAI","slug":"token-introspection-service-unavailable","errorCode":null,"errorMessage":"Token introspection service unavailable","messagePattern":"Token introspection service unavailable","errorType":"http","errorClass":"HTTPException","httpStatus":503,"severity":"error","filePath":"lib/crewai/src/crewai/a2a/auth/server_schemes.py","lineNumber":607,"sourceCode":"                response = await client.post(\n                    str(self.introspection_url),\n                    data={\"token\": token},\n                    auth=(\n                        self.introspection_client_id or \"\",\n                        self.introspection_client_secret.get_secret_value()\n                        if self.introspection_client_secret\n                        else \"\",\n                    ),\n                )\n                response.raise_for_status()\n                introspection_result = response.json()\n\n        except httpx.HTTPStatusError as e:\n            logger.error(\n                \"OAuth2 introspection failed\",\n                extra={\"reason\": \"http_error\", \"status_code\": e.response.status_code},\n            )\n            raise HTTPException(\n                status_code=HTTP_503_SERVICE_UNAVAILABLE,\n                detail=\"Token introspection service unavailable\",\n            ) from None\n        except Exception as e:\n            logger.error(\n                \"OAuth2 introspection failed\",\n                extra={\"reason\": \"unexpected_error\", \"error\": str(e)},\n            )\n            raise HTTPException(\n                status_code=HTTP_503_SERVICE_UNAVAILABLE,\n                detail=\"Token introspection failed\",\n            ) from None\n\n        if not introspection_result.get(\"active\", False):\n            logger.debug(\n                \"OAuth2 authentication failed\",\n                extra={\"reason\": \"token_not_active\", \"scheme\": \"oauth2\"},\n            )","sourceCodeStart":589,"sourceCodeEnd":625,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai/src/crewai/a2a/auth/server_schemes.py#L589-L625","documentation":"Raised by OAuth2ServerAuth._authenticate_introspection() when the RFC 7662 introspection endpoint returns an HTTP error status (response.raise_for_status() throws httpx.HTTPStatusError). It maps to HTTP 503 Service Unavailable — the token was never evaluated because the upstream IdP rejected the introspection call itself. Logged at ERROR level with the upstream status code as reason='http_error'.","triggerScenarios":"Introspection endpoint returns 401 because introspection_client_id/client_secret are wrong (the call is authenticated with HTTP basic auth); 429 rate limiting; 5xx from the IdP; the URL points to a wrong path returning 404.","commonSituations":"Rotated or revoked introspection client credentials; IdP rate limits hit under load; wrong introspection URL copied from docs (v1 vs v2 endpoints); IdP partial outage.","solutions":["Check the logged status_code: 401/403 means bad client credentials — re-register the client and update introspection_client_id/secret.","429 means rate limiting — add backoff/retry with jitter on the caller side or raise IdP quotas.","5xx/404 — verify the introspection_url against the IdP's current documentation.","Retry the original request after a short delay for transient upstream failures."],"exampleFix":"# before\nauth = OAuth2ServerAuth(\n    introspection_url=\"https://idp/v1/introspect\",  # wrong/legacy path -> 404 -> 503\n    introspection_client_id=\"svc\", introspection_client_secret=secret,\n)\n\n# after\nauth = OAuth2ServerAuth(\n    introspection_url=\"https://idp/oauth2/v1/introspect\",  # IdP's documented endpoint\n    introspection_client_id=\"svc\", introspection_client_secret=secret,\n)","handlingStrategy":"retry","validationCode":"import httpx\n\nprobe = httpx.post(\n    introspection_url,\n    data={\"token\": \"probe-token\"},\n    auth=(introspection_client_id, introspection_client_secret),\n    timeout=5,\n)\nassert probe.status_code == 200, (\n    f\"introspection endpoint unhealthy: {probe.status_code} (401/403 = bad client credentials)\"\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 == \"Token introspection service unavailable\":\n            await asyncio.sleep(2 ** attempt)  # upstream IdP error: backoff and retry\n        else:\n            raise","preventionTips":["Keep introspection client credentials in a secret store and rotate them carefully.","Probe the introspection endpoint at startup; a 401 probe means bad client credentials.","Add rate-limit-aware backoff (429 from the IdP surfaces here as 503)."],"tags":["a2a","oauth2","introspection","network","retryable","http-503"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}