apereo/cas · warning
Throttling submission from
Error message
Throttling submission from [{}]. Authentication attempt exceeds the failure threshold [{}] What it means
AbstractThrottledSubmissionHandlerInterceptorAdapter.preHandle decides before authentication whether the request should be throttled. When throttleRequest or exceedsThreshold indicates the failure threshold is met, this warning logs the client's remote address and the configured threshold rate; the throttle is recorded, the submission updated, and the configured throttled request response handler rejects the request.
Solutions
- Investigate the source address for attack activity and block it upstream if malicious.
- Raise the threshold or shorten the range so legitimate users are not throttled.
- Configure a custom ThrottledRequestResponseHandler to return an appropriate response (e.g. 429).
- For shared NAT scenarios, switch the throttle key to username-based instead of IP-based.
Example fix
// before: key by IP only (NAT problem) cas.authn.throttle.app-code=CAS cas.authn.throttle.failure.code=AuthenticationFailed // consider username-based throttle handler or raise threshold cas.authn.throttle.failure.threshold=20
Defensive patterns
Strategy: retry
Validate before calling
// client: avoid rapid consecutive failed attempts
if (lastAuthFailure != null && Duration.between(lastAuthFailure, Instant.now()).getSeconds() < 5)
throw new IllegalStateException("Wait before retrying authentication"); Try / catch
// back off when throttled
try {
casLogin(user, pass);
} catch (HttpClientErrorException e) {
if (e.getStatusCode().value() == 429) {
Thread.sleep(backoffSeconds++ * 1000L);
casLogin(user, pass);
} else throw e;
} Prevention
- Use per-username throttle keys to avoid NAT-shared-IP lockouts.
- Deploy WAF/proxy rate limits upstream of CAS for abusive clients.
- Monitor preHandle throttle warnings as a security signal.
When it happens
Trigger: preHandle finds the request's key already exceeds the failure threshold (via throttleRequest(request,response) or exceedsThreshold(request)) — i.e. too many failed authentications from the same username/IP within the configured rate window.
Common situations: Brute-force/credential-stuffing attempts against /login; misbehaving integration tests replaying failed logins; shared NAT IP causing many users to trip the per-IP threshold.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Throttled submission
- Authentication throttling rate
- Validation attempt for principal is throttled
- Authentication handler is disabled
- No user can be accepted because none is defined
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/2d5dca21c01485d3.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-throttle-core/src/main/java/org/apereo/cas/throttle/AbstractThrottledSubmissionHandlerInterceptorAdapter.java:67
@Override
public void afterPropertiesSet() {
val throttle = getConfigurationContext().getCasProperties().getAuthn().getThrottle().getFailure();
this.thresholdRate = (double) throttle.getThreshold() / throttle.getRangeSeconds();
LOGGER.trace("Calculated threshold rate as [{}]", this.thresholdRate);
}
@Override
public final boolean preHandle(final @NonNull HttpServletRequest request,
final @NonNull HttpServletResponse response,
final @NonNull Object handler) {
if (isRequestIgnoredForThrottling(request, response)) {
LOGGER.trace("Letting the request through without throttling; No request filters support it");
return true;
}
val throttled = throttleRequest(request, response) || exceedsThreshold(request);
if (throttled) {
LOGGER.warn("Throttling submission from [{}]. Authentication attempt exceeds the failure threshold [{}]",
request.getRemoteAddr(), this.thresholdRate);
recordThrottle(request);
updateThrottledSubmission(request);
return configurationContext.getThrottledRequestResponseHandler().handle(request, response);
}
return true;
}
@Override
public final void postHandle(final @NonNull HttpServletRequest request, final @NonNull HttpServletResponse response,
final @NonNull Object handler, final ModelAndView modelAndView) {
if (isRequestIgnoredForThrottling(request, response)) {
LOGGER.trace("Skipping authentication throttling for requests; no filters support it.");
return;
}
val recordEvent = shouldResponseBeRecordedAsFailure(response);
if (recordEvent) {View on GitHub (pinned to e7288fc434)