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 [%s] and resolved providers are [%s]

What it means

GlobalMultifactorAuthenticationTrigger.isActivated found that the globally configured MFA provider ids (cas.authn.mfa.global-provider-id) could not all be resolved against the registered MultifactorAuthenticationProvider selection. handleAbsentMultifactorProvider logs a warning and throws MultifactorAuthenticationProviderAbsentException, failing the flow because a mandated provider is missing.

Solutions

  1. Correct the provider ids in cas.authn.mfa.global-provider-id to match registered provider beans (e.g., mfa-simple, mfa-duo)
  2. Add the missing MFA provider module/dependency and enable its feature so the provider registers
  3. Log available provider ids (the warning shows resolved providers) and align config with that list

Example fix

// before
cas.authn.mfa.global-provider-id=mfa-gauth,mfa-duoo
// after
cas.authn.mfa.global-provider-id=mfa-gauth,mfa-duo
Defensive patterns

Strategy: try-catch

Validate before calling

var resolved = providerSelector.getAvailableProviders(); var missing = globalIds.stream().filter(id -> resolved.stream().noneMatch(p -> p.getId().equals(id))).toList(); if (!missing.isEmpty()) { /* fix config before login */ }

Try / catch

try { mfaTrigger.isActivated(...); } catch (MultifactorAuthenticationProviderAbsentException e) { log.error("configured MFA provider missing: {}", e.getMessage()); }

Prevention

When it happens

Trigger: cas.authn.mfa.global-provider-id lists provider ids (comma-separated) and at least one has no matching registered MultifactorAuthenticationProvider when isActivated runs.

Common situations: Typo in global-provider-id; MFA provider module not added to the overlay so its provider bean never registers; provider id changed after a CAS upgrade; provider conditionally disabled by feature toggle.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/2b353512002efc16. 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:119

            })
            .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)