{"record":{"id":"0604ad5d32d748fe","repo":"apereo/cas","slug":"authentication-chain-is-empty-as-no-authentication","errorCode":null,"errorMessage":"Authentication chain is empty as no authentications have been collected","messagePattern":"Authentication chain is empty as no authentications have been collected","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/DefaultAuthenticationResultBuilder.java","lineNumber":48,"sourceCode":"    private final List<Credential> providedCredentials = new ArrayList<>();\n\n    private final PrincipalElectionStrategy principalElectionStrategy;\n\n    /**\n     * Principal id is and must be enforced to be the same for all authentications.\n     * Based on that restriction, it's safe to grab the first principal id in the chain\n     * when composing the authentication chain for the caller.\n     */\n    private static @Nullable Principal getPrimaryPrincipal(final PrincipalElectionStrategy principalElectionStrategy,\n                                                 final Set<Authentication> authentications,\n                                                 final Map<String, List<Object>> principalAttributes) throws Throwable {\n        return principalElectionStrategy.nominate(new LinkedHashSet<>(authentications), principalAttributes);\n    }\n\n    @Override\n    public Optional<Authentication> getInitialAuthentication() {\n        if (this.authentications.isEmpty()) {\n            LOGGER.warn(\"Authentication chain is empty as no authentications have been collected\");\n        }\n\n        synchronized (this.authentications) {\n            return this.authentications.stream().findFirst();\n        }\n    }\n\n    @Override\n    public Optional<Credential> getInitialCredential() {\n        if (this.providedCredentials.isEmpty()) {\n            LOGGER.warn(\"Provided credentials chain is empty as no credentials have been collected\");\n        }\n        return providedCredentials.stream().findFirst();\n    }\n\n    @Override\n    @CanIgnoreReturnValue\n    public AuthenticationResultBuilder collect(final Authentication authentication) {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/DefaultAuthenticationResultBuilder.java#L30-L66","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","solutions":["Ensure DefaultAuthenticationManager.authenticate(...) completed before requesting the initial authentication.","Check callers for early return paths that skip authentication but still build an AuthenticationResult.","In tests, seed the builder with a populated Authentication before asserting on getInitialAuthentication()."],"exampleFix":"// before\nval initial = resultBuilder.getInitialAuthentication(); // always empty\n// after\nval auth = authenticationManager.authenticate(transaction);\nresultBuilder.collect(auth);\nval initial = resultBuilder.getInitialAuthentication();","handlingStrategy":"type-guard","validationCode":"if (resultBuilder.getInitialAuthentication().isEmpty()) {\n    // authentication never ran — rerun the manager before proceeding\n}","typeGuard":"Optional<Authentication> maybeAuth = resultBuilder.getInitialAuthentication();\nif (maybeAuth.isPresent()) {\n    Authentication auth = maybeAuth.get();\n    // safe use\n}","tryCatchPattern":null,"preventionTips":["Always flow through DefaultAuthenticationManager before touching the result builder.","Treat Optional.empty() as an error condition in custom webflow actions."],"tags":["authentication","empty-state","webflow"],"backgroundTag":"empty-result-set","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}