apereo/cas · warning

Principal resolution handled by

Error message

Principal resolution handled by [{}] produced a null principal for: [{}]CAS is configured to treat principal resolution failures as fatal.

What it means

When principal resolution yields a null principal and cas.authn.principalResolutionFailureFatal is true, DefaultAuthenticationManager.authenticateAndResolvePrincipal logs this warning and throws UnresolvedPrincipalException, aborting authentication. CAS is configured to treat a failed resolution as fatal rather than falling back to the handler's principal.

Solutions

  1. Verify the underlying attribute repository (LDAP/JDBC/etc.) has a record for the resolved user.
  2. Set cas.authn.principalResolutionFailureFatal=false to fall back to the handler-produced principal (only if acceptable).
  3. Fix resolver configuration so it supports the credential (see error 360).
  4. Inspect the preceding ERROR log line '[resolver] failed to resolve principal' for the root cause exception.

Example fix

// before
cas.authn.principal-resolution-failure-fatal=true
// after (allow fallback to handler principal)
cas.authn.principal-resolution-failure-fatal=false
Defensive patterns

Strategy: try-catch

Validate before calling

val resolved = principalResolver.resolve(credential);
if (resolved == null) {
    // fix attribute source before enabling fatal mode
}

Try / catch

try {
    authenticationManager.authenticate(transaction);
} catch (UnresolvedPrincipalException e) {
    LOGGER.error("Principal resolution failed for {}", transaction.getCredentials(), e);
    // present a user-friendly failure or repair attribute repository
}

Prevention

When it happens

Trigger: principalResolutionFailureFatal=true and resolvePrincipal (or the handler result itself) returns null — e.g. resolver unsupported credential (see [360]), empty attribute repository result, or handler produced no principal.

Common situations: Strict deployments where principal MUST come from the attribute source (LDAP/JDBC) but the attribute repository is down or the user record is missing; misconfigured resolver so resolution silently fails; principal mapping/removal of attributes results in null.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/c5ea4933f6c493e5. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/DefaultAuthenticationManager.java:169

                                                   final AuthenticationHandler handler,
                                                   final Service service) throws Throwable {
        val clientInfo = ClientInfoHolder.getClientInfo();
        publishEvent(new CasAuthenticationTransactionStartedEvent(this, credential, clientInfo));

        try {
            AuthenticationHolder.setCurrentAuthentication(authenticationBuilder.build());
            val handlerExecutionResult = handler.authenticate(credential, service);
            val authenticationHandlerName = handler.getName();
            authenticationBuilder.addSuccess(authenticationHandlerName, handlerExecutionResult);
            LOGGER.debug("Authentication handler [{}] successfully authenticated [{}]", authenticationHandlerName, credential);
            publishEvent(new CasAuthenticationTransactionSuccessfulEvent(this, credential, clientInfo));
            var principal = principalResolver != null
                ? resolvePrincipal(handler, principalResolver, credential, handlerExecutionResult.getPrincipal(), service)
                : handlerExecutionResult.getPrincipal();
            if (principal == null) {
                val resolverName = principalResolver == null ? authenticationHandlerName : principalResolver.getName();
                if (this.principalResolutionFailureFatal) {
                    LOGGER.warn("Principal resolution handled by [{}] produced a null principal for: [{}]"
                        + "CAS is configured to treat principal resolution failures as fatal.", resolverName, credential);
                    throw new UnresolvedPrincipalException();
                }
                LOGGER.warn("Principal resolution handled by [{}] produced a null principal. "
                    + "This is likely due to misconfiguration or missing attributes; CAS will attempt to use the principal "
                    + "produced by the authentication handler, if any.", resolverName);
            } else {
                val currentPrincipal = authenticationBuilder.getPrincipal();
                if (!(currentPrincipal instanceof NullPrincipal)) {
                    val merger = authenticationSystemSupport.getObject().getPrincipalElectionStrategy().getAttributeMerger();
                    LOGGER.trace("Merging attributes from [{}] into principal [{}]", principal, currentPrincipal);
                    val mergedAttributes = CoreAuthenticationUtils.mergeAttributes(currentPrincipal.getAttributes(), principal.getAttributes(), merger);
                    principal = principal.withAttributes(mergedAttributes);
                    LOGGER.debug("Merged attributes into principal [{}]", principal);
                }
                authenticationBuilder.setPrincipal(principal);
            }
            LOGGER.debug("Final principal resolved for this authentication event is [{}]", principal);

View on GitHub (pinned to e7288fc434)