crewAIInc/crewAI · critical · HTTPException
OAuth2 introspection not configured
Error message
OAuth2 introspection not configured
What it means
Raised by OAuth2ServerAuth._authenticate_introspection() when it is invoked but introspection_url is empty. It maps to HTTP 500: the internal state (routing to introspection without an introspection endpoint) contradicts the model validator's guarantee, so in practice it indicates an object that bypassed normal construction or was mutated after validation.
Source
Thrown at lib/crewai/src/crewai/a2a/auth/server_schemes.py:582
raise HTTPException(
status_code=HTTP_503_SERVICE_UNAVAILABLE,
detail="Unable to fetch signing keys",
) from None
except jwt.InvalidTokenError as e:
logger.debug(
"OAuth2 authentication failed",
extra={"reason": "invalid_token", "error": str(e), "scheme": "oauth2"},
)
raise HTTPException(
status_code=HTTP_401_UNAUTHORIZED,
detail="Invalid or missing authentication credentials",
) from None
async def _authenticate_introspection(self, token: str) -> AuthenticatedUser:
"""Authenticate using OAuth2 token introspection (RFC 7662)."""
if not self.introspection_url:
raise HTTPException(
status_code=HTTP_500_INTERNAL_SERVER_ERROR,
detail="OAuth2 introspection not configured",
)
try:
async with httpx.AsyncClient() as client:
response = await client.post(
str(self.introspection_url),
data={"token": token},
auth=(
self.introspection_client_id or "",
self.introspection_client_secret.get_secret_value()
if self.introspection_client_secret
else "",
),
)
response.raise_for_status()
introspection_result = response.json()View on GitHub (pinned to 754d7323be)
Solutions
- Construct OAuth2ServerAuth normally with introspection_url so validation guarantees consistency.
- Avoid model_construct() and in-place mutation of auth scheme objects; rebuild them instead.
- Add a startup sanity check: the scheme must have _jwk_client or a non-empty introspection_url.
- If deserializing from config, round-trip through OAuth2ServerAuth.model_validate().
Example fix
# before
auth = OAuth2ServerAuth.model_construct() # no endpoints; introspection path -> 500
# after
auth = OAuth2ServerAuth(
introspection_url="https://idp/oauth/introspect",
introspection_client_id="svc",
introspection_client_secret="***",
) Defensive patterns
Strategy: validation
Validate before calling
from crewai.a2a.auth.server_schemes import OAuth2ServerAuth
auth = OAuth2ServerAuth(
introspection_url="https://idp/oauth/introspect",
introspection_client_id="svc",
introspection_client_secret="***",
)
assert auth.introspection_url, "introspection must be configured when used" Type guard
def is_introspection_ready(scheme) -> bool:
"""True when the scheme can call an introspection endpoint."""
return bool(getattr(scheme, "introspection_url", None)) Prevention
- Build schemes with model_validate/__init__ only, never model_construct().
- Do not mutate auth scheme attributes after construction.
- Prefer raising a startup error over letting an inconsistent scheme serve 500s.
When it happens
Trigger: authenticate() dispatches to _authenticate_introspection() because _jwk_client is None, yet introspection_url was also cleared — only reachable via model_construct() or manual attribute surgery, since a validly constructed scheme has at least one endpoint.
Common situations: Tests that build schemes with model_construct(); code that reassigns config fields post-construction; framework code deserializing schemes without running validators.
Related errors
- OAuth2 JWKS not initialized
- OIDC not initialized
- introspection_client_id and introspection_client_secret are
- Token introspection service unavailable
- Error. A valid pyproject.toml file is required. Check that a
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/8440d20f3bd49bb5.
Report an issue: GitHub.