apereo/cas · warning

Authentication chain is empty as no authentications have…

Error message

Authentication chain is empty as no authentications have been collected

What it means

DefaultAuthenticationResultBuilder.getInitialAuthentication logs a warning when no Authentication objects have been collected in the builder, then returns Optional.empty(). It signals the authentication chain is empty, so callers asking for the initial authentication get nothing.

Solutions

  1. Ensure DefaultAuthenticationManager.authenticate(...) completed before requesting the initial authentication.
  2. Check callers for early return paths that skip authentication but still build an AuthenticationResult.
  3. In tests, seed the builder with a populated Authentication before asserting on getInitialAuthentication().

Example fix

// before
val initial = resultBuilder.getInitialAuthentication(); // always empty
// after
val auth = authenticationManager.authenticate(transaction);
resultBuilder.collect(auth);
val initial = resultBuilder.getInitialAuthentication();
Defensive patterns

Strategy: type-guard

Validate before calling

if (resultBuilder.getInitialAuthentication().isEmpty()) {
    // authentication never ran — rerun the manager before proceeding
}

Type guard

Optional<Authentication> maybeAuth = resultBuilder.getInitialAuthentication();
if (maybeAuth.isPresent()) {
    Authentication auth = maybeAuth.get();
    // safe use
}

Prevention

When it happens

Trigger: Calling getInitialAuthentication() on a DefaultAuthenticationResultBuilder before any authentication has been recorded via build/authentication population (e.g. during a flow step that never completed authentication).

Common situations: Webflow reached the result builder without executing the authentication manager (e.g. session expired, direct flow invocation in custom code, tests constructing the builder manually).

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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

Appendix: source

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

    private final List<Credential> providedCredentials = new ArrayList<>();

    private final PrincipalElectionStrategy principalElectionStrategy;

    /**
     * Principal id is and must be enforced to be the same for all authentications.
     * Based on that restriction, it's safe to grab the first principal id in the chain
     * when composing the authentication chain for the caller.
     */
    private static @Nullable Principal getPrimaryPrincipal(final PrincipalElectionStrategy principalElectionStrategy,
                                                 final Set<Authentication> authentications,
                                                 final Map<String, List<Object>> principalAttributes) throws Throwable {
        return principalElectionStrategy.nominate(new LinkedHashSet<>(authentications), principalAttributes);
    }

    @Override
    public Optional<Authentication> getInitialAuthentication() {
        if (this.authentications.isEmpty()) {
            LOGGER.warn("Authentication chain is empty as no authentications have been collected");
        }

        synchronized (this.authentications) {
            return this.authentications.stream().findFirst();
        }
    }

    @Override
    public Optional<Credential> getInitialCredential() {
        if (this.providedCredentials.isEmpty()) {
            LOGGER.warn("Provided credentials chain is empty as no credentials have been collected");
        }
        return providedCredentials.stream().findFirst();
    }

    @Override
    @CanIgnoreReturnValue
    public AuthenticationResultBuilder collect(final Authentication authentication) {

View on GitHub (pinned to e7288fc434)