apereo/cas · warning
The request is throttled as capacity is entirely consumed…
Error message
The request is throttled as capacity is entirely consumed. Available tokens are [{}] What it means
This WARN indicates the rate-limit bucket is exhausted: bucket.tryConsume returned false, so the request is throttled. CAS computes a Retry-After value from the bucket refill probe and returns a BucketConsumptionResult with consumed=false plus X-Rate-Limit headers.
Solutions
- Tune capacity/refill settings (e.g. cas.authn.throttle capacity and refill duration) to match legitimate traffic.
- Verify the bucket key granularity so distinct users/clients are not throttled collectively.
- If the client is yours, add backoff honoring the returned retryAfterSeconds / X-Rate-Limit-Retry-After-Seconds header.
- Check for abusive traffic sources and block them upstream.
Example fix
// before cas.authn.throttle.capacity=10 cas.authn.throttle.refill-duration=PT1H // after cas.authn.throttle.capacity=100 cas.authn.throttle.refill-duration=PT1M
Defensive patterns
Strategy: retry
Validate before calling
// client-side: check remaining tokens before next call const remaining = Number(response.headers['x-rate-limit-remaining']); if (remaining === 0) await sleep(Number(response.headers['x-rate-limit-retry-after-seconds']) * 1000);
Try / catch
BucketConsumptionResult r = bucketConsumer.consume(key);
if (!r.isConsumed()) {
long wait = r.getRetryAfterSeconds();
Thread.sleep(TimeUnit.SECONDS.toMillis(wait));
r = bucketConsumer.consume(key);
} Prevention
- Honor Retry-After / X-Rate-Limit-Retry-After-Seconds headers with exponential backoff.
- Size bucket capacity to legitimate peak traffic, not average traffic.
- Key buckets per user/client, not globally, to avoid cross-user throttling.
- Alert on sustained throttling to detect brute-force or retry storms.
When it happens
Trigger: consume() is called when all tokens in the bucket are already consumed (canProceed is false); happens on every request once the allowed rate is exceeded within the refill window.
Common situations: Client retry storms or brute-force attempts exhausting the throttle budget; overly aggressive rate-limit configuration (small capacity, long refill period); shared buckets keyed too broadly (e.g. same key for all users behind one proxy IP).
Related errors
- Unable to obtain a bucket for
- Validation attempt for principal is throttled
- Throttled submission
- Throttling submission from
- Authentication throttling rate
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/a938eea5aa948c0b.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-bucket4j-core/src/main/java/org/apereo/cas/bucket4j/consumer/DefaultBucketConsumer.java:56
val canProceed = FunctionUtils.doAndHandle(() -> {
if (properties.isBlocking()) {
LOGGER.debug("Attempting to consume a token for the authentication attempt");
return bucket.tryConsume(1, MAX_WAIT_NANOS, BlockingStrategy.PARKING);
}
return bucket.tryConsume(1);
}, e -> {
LoggingUtils.error(LOGGER, e);
Thread.currentThread().interrupt();
return false;
}).get();
val headers = new LinkedHashMap<String, String>();
val availableTokens = bucket.getAvailableTokens();
if (!canProceed) {
val probe = bucket.tryConsumeAndReturnRemaining(1);
val seconds = TimeUnit.NANOSECONDS.toSeconds(probe.getNanosToWaitForRefill());
headers.put(HEADER_NAME_X_RATE_LIMIT_RETRY_AFTER_SECONDS, Long.toString(seconds));
LOGGER.warn("The request is throttled as capacity is entirely consumed. Available tokens are [{}]", availableTokens);
return BucketConsumptionResult.builder()
.retryAfterSeconds(seconds)
.tokensRemaining(availableTokens)
.consumed(false).headers(headers).build();
}
headers.put(HEADER_NAME_X_RATE_LIMIT_REMAINING, Long.toString(availableTokens));
return BucketConsumptionResult.builder()
.tokensRemaining(availableTokens)
.consumed(true).headers(headers).build();
});
}
}
View on GitHub (pinned to e7288fc434)