PrefectHQ/fastmcp · error · IdentityAssertionError
Server overloaded, please retry
Error message
Server overloaded, please retry
What it means
Raised when the jti replay cache has reached its configured maximum size (jti_cache_max_size), an expired-entry cleanup pass fails to free any space, and the incoming assertion's jti therefore cannot be inserted. The library refuses to grow the cache and rejects the assertion with a backpressure-style 'server overloaded' error rather than accepting it untracked.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/identity_assertion.py:467
# cache lookup (a 500) instead of a clean invalid_grant.
jti = claims.get("jti")
if not jti or not isinstance(jti, str):
raise IdentityAssertionError("Assertion must include a string jti claim")
cached_exp = self._jti_cache.get(jti)
if cached_exp is not None and cached_exp > now:
raise IdentityAssertionError(f"Assertion replay detected: jti {jti} reused")
# Enforce the cap BEFORE inserting so a rejected assertion never grows the
# cache. A fresh jti that would exceed capacity is rejected outright (after
# a cleanup pass to reclaim any expired entries first).
if (
jti not in self._jti_cache
and len(self._jti_cache) >= self._jti_cache_max_size
):
self._cleanup_expired_jtis()
if len(self._jti_cache) >= self._jti_cache_max_size:
logger.warning("ID-JAG jti cache at capacity, possible attack")
raise IdentityAssertionError("Server overloaded, please retry")
self._jti_cache[jti] = exp
logger.debug("ID-JAG validated for subject=%s issuer=%s", sub, iss)
return claims
def normalize_resource_url(url: str) -> str:
"""Normalize a resource URL by removing query parameters and trailing slashes.
RFC 8707 allows clients to include query parameters in resource URLs, but
the server's configured resource URL typically doesn't include them. This
normalizes both sides for comparison by stripping query and fragment.
"""
parsed = urlparse(str(url))
return urlunparse(
(parsed.scheme, parsed.netloc, parsed.path.rstrip("/"), "", "", "")
)
View on GitHub (pinned to 1f02114297)
Solutions
- Increase the jti cache max size (jti_cache_max_size / settings) to cover peak assertions × TTL
- Shorten assertion token lifetime (exp) so jti entries expire and free cache capacity faster
- Check whether the volume is an attack and apply rate limiting / WAF rules upstream
- Retry with backoff — the error is transient: entries expire and capacity is reclaimed
- Monitor the 'ID-JAG jti cache at capacity' warning to size capacity from real traffic
Example fix
// before IdentityAssertion(jti_cache_max_size=1000) // after IdentityAssertion(jti_cache_max_size=100_000) # sized for peak_rps * ttl_seconds
Defensive patterns
Strategy: retry
Try / catch
try:
validate(assertion)
except IdentityAssertionError as e:
if "Server overloaded" in str(e):
time.sleep(backoff)
validate(mint_new_assertion()) # retry with backoff, fresh jti
else:
raise Prevention
- Size jti_cache_max_size for peak assertion rate × token TTL
- Keep assertion TTLs short so cache entries expire quickly
- Apply upstream rate limiting to shield the validation endpoint
- Alert on the 'jti cache at capacity' warning log
When it happens
Trigger: More than _jti_cache_max_size distinct, still-unexpired jti values are validated within their TTL window, e.g. a burst of legitimate traffic, a flood of unique assertions, or an attack flooding the endpoint with valid-format assertions, after _cleanup_expired_jtis() reclaims nothing (identity_assertion.py:462-467).
Common situations: High-volume production traffic with the default cache size too small; assertion TTLs much longer than the validation rate makes room for; a denial-of-service flooding valid assertions; load tests exceeding capacity.
Related errors
- OAuth client not found - cached credentials may be stale
- OAuth server rejected the static client credentials. Verify
- module {__name__!r} has no attribute {name!r}
- Subclasses must implement verify_token
- MultiAuth requires at least a server or one verifier
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/d0a43da4bd5baa66.
Report an issue: GitHub.