apereo/cas · error · MultifactorAuthenticationProviderAbsentException
Not all requested multifactor providers could be found…
Error message
Not all requested multifactor providers could be found. Requested providers are [<globalProviderIds>] and resolved providers are [<providerIds>]
What it means
GlobalMultifactorAuthenticationTrigger compares the globally requested MFA provider ids (cas.authn.mfa.global-provider-id, or from the principal attributes) against the providers actually resolved/registered in the CAS context. If any requested id has no matching MultifactorAuthenticationProvider bean, handleAbsentMultifactorProvider logs a warning and throws MultifactorAuthenticationProviderAbsentException, treating MFA as unsatisfiable.
Solutions
- Add/enable the CAS module that provides the missing provider (e.g. cas-server-support-gauth, duo, otp-mfa) so its auto-configuration registers the bean.
- Correct cas.authn.mfa.global-provider-id (and any principal-attribute provider ids) to match a registered provider id; check resolved ids in the WARN log.
- Verify the provider's feature/condition is enabled in cas.features (module present but inactive).
- If MFA should be optional, remove the global provider id instead of referencing a nonexistent provider.
Example fix
// before cas.authn.mfa.global-provider-id=mfa-duo // duo module not on classpath // after: add dependency + matching config, or use an enabled provider implementation "org.apereo.cas:cas-server-support-duo" cas.authn.mfa.duo[0].registry-name=...
Defensive patterns
Strategy: validation
Validate before calling
val ids = casProperties.getAuthn().getMfa().getGlobalProviderId()
val available = providers.map { it.getId() }.toSet()
if (ids != null && !available.containsAll(Arrays.asList(ids.split(",")))) {
throw new IllegalStateException("Unresolved MFA provider ids configured");
} Try / catch
try { return trigger.isActivated(principal, service, request, context); }
catch (MultifactorAuthenticationProviderAbsentException e) {
LOGGER.error("MFA provider missing", e);
return Optional.empty();
} Prevention
- Add the support module for every referenced mfa-* provider id
- Validate global-provider-id values against resolved ids at startup
- Avoid hand-typing provider ids; copy them from documentation/log output
When it happens
Trigger: isActivated (or shouldMultifactorAuthenticatorsBeActivated) runs while cas.authn.mfa.global-provider-id (or the request/principal-supplied provider ids) references an id such as 'mfa-duo' for which no provider module/bean is registered.
Common situations: Setting global-provider-id but forgetting to include the corresponding provider dependency (e.g. cas-server-support-otp-mfa) and its configuration; typo in provider id (ids are like 'mfa-gauth', 'mfa-duo', 'mfa-simple'); provider bean filtered out by disabled feature conditions; copying config from another environment where the module is enabled.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- List of candidate multifactor authentication providers is…
- MultifactorAuthenticationProviderAbsentException
- ACR [ ] is not defined as a supported ACR in CAS…
- Device registration is disabled for
- Unable to register multiple devices for
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/6191700089fb2b09.
Report an issue: GitHub.
Appendix: source
Thrown at core/cas-server-core-authentication-mfa-api/src/main/java/org/apereo/cas/authentication/mfa/trigger/GlobalMultifactorAuthenticationTrigger.java:118
return StringUtils.commaDelimitedListToSet(globalProviderId);
})
.filter(providers -> !providers.isEmpty())
.orElseGet(() -> {
val globalProviderId = casProperties.getAuthn().getMfa().getTriggers().getGlobal().getGlobalProviderId();
return StringUtils.commaDelimitedListToSet(globalProviderId);
});
}
protected void handleAbsentMultifactorProvider(final Set<String> globalProviderIds,
final List<MultifactorAuthenticationProvider> resolvedProviders) {
val providerIds = resolvedProviders
.stream()
.map(MultifactorAuthenticationProvider::getId)
.collect(Collectors.joining(","));
val message = String.format("Not all requested multifactor providers could be found. "
+ "Requested providers are [%s] and resolved providers are [%s]", globalProviderIds, providerIds);
LOGGER.warn(message, globalProviderIds);
throw new MultifactorAuthenticationProviderAbsentException(message);
}
protected Optional<MultifactorAuthenticationProvider> resolveSingleMultifactorProvider(
final MultifactorAuthenticationProvider resolvedProvider) {
LOGGER.debug("Resolved single multifactor provider [{}]", resolvedProvider);
return Optional.of(resolvedProvider);
}
protected Optional<MultifactorAuthenticationProvider> resolveMultifactorProvider(
final Authentication authentication,
final RegisteredService registeredService,
final List<MultifactorAuthenticationProvider> resolvedProviders) throws Throwable {
val principal = authentication.getPrincipal();
val provider = multifactorAuthenticationProviderSelector.resolve(resolvedProviders, registeredService, principal);
LOGGER.debug("Selected multifactor authentication provider for this transaction is [{}]", provider);
return Optional.ofNullable(provider);
}
}View on GitHub (pinned to e7288fc434)