{"record":{"id":"6f4f2b7cd7df4e14","repo":"apereo/cas","slug":"unable-to-locate-authentication-object-in-the-webf","errorCode":null,"errorMessage":"Unable to locate authentication object in the webflow context","messagePattern":"Unable to locate authentication object in the webflow context","errorType":"exception","errorClass":"AuthenticationException","httpStatus":401,"severity":"error","filePath":"core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/resolver/impl/DefaultCasDelegatingWebflowEventResolver.java","lineNumber":98,"sourceCode":"            val registeredService = determineRegisteredServiceForEvent(context, service);\n            LOGGER.trace(\"Attempting to resolve candidate authentication events for service [{}]\", service);\n            val resolvedEvents = resolveCandidateAuthenticationEvents(context, service, registeredService);\n            if (resolvedEvents.isEmpty()) {\n                LOGGER.trace(\"No candidate authentication events were resolved for service [{}]\", service);\n            } else {\n                LOGGER.trace(\"Authentication events resolved for [{}] are [{}]. Selecting final event...\", service, resolvedEvents);\n                WebUtils.putResolvedEventsAsAttribute(context, resolvedEvents);\n                val finalResolvedEvent = this.selectiveResolver.resolveSingle(context);\n                LOGGER.debug(\"The final authentication event resolved for [{}] is [{}]\", service, finalResolvedEvent);\n                if (finalResolvedEvent != null) {\n                    return CollectionUtils.wrapSet(finalResolvedEvent);\n                }\n            }\n\n            val builder = WebUtils.getAuthenticationResultBuilder(context);\n            if (builder == null) {\n                val msg = \"Unable to locate authentication object in the webflow context\";\n                throw new IllegalArgumentException(new AuthenticationException(msg));\n            }\n            return CollectionUtils.wrapSet(grantTicketGrantingTicketToAuthenticationResult(context, builder, service));\n        } catch (final Throwable exception) {\n            val event = buildEventFromException(exception, context, credentials, service);\n            val response = WebUtils.getHttpServletResponseFromExternalWebflowContext(context);\n            response.setStatus(HttpStatus.UNAUTHORIZED.value());\n            LOGGER.debug(\"Authentication request failed with [{}], resulting in event [{}]\", response.getStatus(), event);\n            return CollectionUtils.wrapSet(event);\n        }\n    }\n\n    @Override\n    public void addDelegate(final CasWebflowEventResolver resolver) {\n        if (BeanSupplier.isNotProxy(resolver)) {\n            orderedResolvers.add(resolver);\n        }\n    }\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/resolver/impl/DefaultCasDelegatingWebflowEventResolver.java#L80-L116","documentation":"DefaultCasDelegatingWebflowEventResolver.resolveInternal requires an in-progress AuthenticationResultBuilder in the webflow context before granting a TGT. If WebUtils.getAuthenticationResultBuilder(context) returns null, no authentication result was staged in this flow request, so it throws IllegalArgumentException wrapping AuthenticationException, typically surfaced as HTTP 401 via buildEventFromException handling.","triggerScenarios":"Resolving the authentication event outside the normal login flow (e.g. a direct POST to the event resolver or a service-ticket/renew request) where WebUtils.getAuthenticationResultBuilder has never been populated; hitting the resolver mid-flow after context reset; calling resolveFrom before any credentials were submitted.","commonSituations":"Direct-deep-linking into a flow state; SSO/session expiry wiping the flow scope; custom webflow actions clearing request context; misconfigured flow transitions skipping the credential-submission step.","solutions":["Ensure the request goes through the standard CAS login flow so the AuthenticationResultBuilder is placed into flow scope before event resolution","If integrating programmatically, first call WebUtils.putAuthenticationResultBuilder(context, builder) with a populated builder","Check that authentication session management is enabled and the authn session hasn't expired mid-flow","Clear stale flow execution state and restart the login flow"],"exampleFix":"// before: calling resolver without a builder\nval events = casWebflowEventResolver.resolve(context, credential, service);\n// after\nval builder = WebUtils.getAuthenticationResultBuilder(context);\nif (builder == null) {\n    builder = new DefaultAuthenticationResultBuilder(...); // or route through /login\n}\nWebUtils.putAuthenticationResultBuilder(context, builder);\nval events = casWebflowEventResolver.resolve(context, credential, service);","handlingStrategy":"type-guard","validationCode":"if (WebUtils.getAuthenticationResultBuilder(context) == null) {\n    // redirect to /login instead of resolving events\n}","typeGuard":"AuthenticationResultBuilder builder = WebUtils.getAuthenticationResultBuilder(context);\nboolean canResolve = builder != null;","tryCatchPattern":"try {\n    return resolver.resolve(context, credentials, service);\n} catch (IllegalArgumentException | AuthenticationException e) {\n    response.setStatus(HttpStatus.UNAUTHORIZED.value());\n    return Collections.emptySet();\n}","preventionTips":["Always route event resolution through the standard login flow","Populate AuthenticationResultBuilder in flow scope before resolving events","Watch for session expiry mid-flow; require fresh login when the builder is gone"],"tags":["webflow","authentication","spring-webflow"],"backgroundTag":"authentication-required","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"}