apereo/cas · warning
No risk calculators are available to evaluate…
Error message
No risk calculators are available to evaluate authentication risk. CAS will proceed to regard the authentication attempt as highly risky. Examine your configuration and ensure at least one risk calculator is available and enabled to correctly assess authentication risk.
What it means
DefaultAuthenticationRiskEvaluator.evaluate() requires at least one configured AuthenticationRiskCalculator to produce a risk score. When the calculators collection is empty it logs this warning and returns AuthenticationRiskScore.highestRiskScore(), meaning every authentication is treated as maximally risky — downstream risk response (usually MFA or blocking) will fire for all logins. This is a misconfiguration signal, not a runtime failure of the evaluator itself.
Solutions
- Enable at least one risk calculator feature in cas.authn.adaptive.risk (e.g. request, dateTime, or geo calculators) and confirm its module is on the classpath.
- Inspect the context for AuthenticationRiskCalculator beans; add a custom one if none exist.
- If risk evaluation is not actually needed, disable cas.authn.adaptive.risk entirely so this evaluator is not engaged.
- Review startup logs for the auto-configuration of the risk module to see why no calculators were created.
Example fix
// before: risk enabled, no calculators cas.authn.adaptive.risk.enabled=true // after: enable at least one calculator source cas.authn.adaptive.risk.enabled=true cas.authn.adaptive.risk.request.enabled=true cas.authn.adaptive.risk.dateTime.enabled=true
Defensive patterns
Strategy: fallback
Validate before calling
val calculators = applicationContext.getBeansOfType(AuthenticationRiskCalculator.class);
if (calculators.isEmpty() && casProperties.getAuthn().getAdaptive().getRisk().isEnabled()) {
throw new IllegalStateException("Risk enabled but no AuthenticationRiskCalculator beans registered");
} Try / catch
try {
val score = riskEvaluator.evaluate(authentication, service, clientInfo);
} catch (Exception e) {
// fall back to a conservative-but-configured score
val score = AuthenticationRiskScore.defaultRiskScore();
} Prevention
- Smoke-test the risk engine at startup: assert at least one calculator bean exists when risk is enabled.
- Enable risk sub-features together with the risk module itself.
- Write an integration test that runs evaluate() with the production configuration.
- Pin CAS modules so calculator-contributing dependencies are not accidentally dropped from the overlay.
When it happens
Trigger: The adaptive/risk feature is enabled (cas.authn.adaptive.risk.enabled=true) but no risk calculator bean (e.g. DefaultAuthenticationRequestRiskCalculator, DefaultAuthenticationDateTimeRiskCalculator, geo-location calculators) is registered or enabled in the application context.
Common situations: Enabling risk-based auth without enabling any of its component features (e.g. not enabling the IP-intelligence/geo modules that contribute calculators); a custom configuration that overrides the evaluator bean and forgets to inject calculators; module dependency missing so calculator auto-configuration never runs.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- No multifactor authentication providers are available in…
- No multifactor authentication providers are specified to…
- List of candidate multifactor authentication providers is…
- Unable to use 'none' as introspection signing algorithm
- Unable to use 'none' as introspection encryption algorithm
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/dd00618338669365.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-electrofence/src/main/java/org/apereo/cas/impl/engine/DefaultAuthenticationRiskEvaluator.java:48
@Getter
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true, value = CasEventRepository.TRANSACTION_MANAGER_EVENTS)
public class DefaultAuthenticationRiskEvaluator implements AuthenticationRiskEvaluator {
private final List<AuthenticationRequestRiskCalculator> calculators;
private final CasConfigurationProperties casProperties;
private final CasEventRepository casEventRepository;
@Audit(action = AuditableActions.EVALUATE_RISKY_AUTHENTICATION,
actionResolverName = AuditActionResolvers.ADAPTIVE_RISKY_AUTHENTICATION_ACTION_RESOLVER,
resourceResolverName = AuditResourceResolvers.ADAPTIVE_RISKY_AUTHENTICATION_RESOURCE_RESOLVER)
@Override
public AuthenticationRiskScore evaluate(final Authentication authentication,
final RegisteredService service,
final ClientInfo clientInfo) {
if (calculators.isEmpty()) {
LOGGER.warn("No risk calculators are available to evaluate authentication risk. "
+ "CAS will proceed to regard the authentication attempt as highly risky. Examine your configuration "
+ "and ensure at least one risk calculator is available and enabled to correctly assess authentication risk.");
return AuthenticationRiskScore.highestRiskScore();
}
val scores = calculators
.stream()
.map(riskCalculator -> riskCalculator.calculate(authentication, service, clientInfo))
.filter(Objects::nonNull)
.toList();
LOGGER.debug("Collected [{}] risk scores from [{}] risk calculators", scores.size(), calculators.size());
val sum = scores
.stream()
.map(AuthenticationRiskScore::getScore)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
val score = sum.divide(BigDecimal.valueOf(calculators.size()), 2, RoundingMode.UP);View on GitHub (pinned to e7288fc434)