apereo/cas · error · ClientFlowExecutionRepositoryException

Webflow execution key is invalid

Error message

Webflow execution key is invalid

What it means

Webflow session pinning is enabled and the restored flow execution's stored user-agent or client IP does not match the current request's, or those values were blank. The execution key is treated as invalid or tampered and ClientFlowExecutionRepositoryException is thrown. The input at fault is the flow execution key (its pinned session attributes vs. current client info).

Solutions

  1. Restart the flow with a fresh execution key
  2. Check for clients whose user-agent or IP legitimately changes mid-flow (proxies, mobile handoff)
  3. Disable webflow session pinning (cas.webflow.session.pinToSession=false) if not required
  4. Investigate the logged mismatch to rule out actual key tampering/replay
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/executor/ClientFlowExecutionRepository.java:156 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/executor/ClientFlowExecutionRepository.java:156

        execution.getConversationScope().put(WEBFLOW_CLIENT_IP_ADDRESS, clientInfo.getClientIpAddress());
    }

    protected void verifyWebflowSessionIsCorrectlyPinned(final SerializedFlowExecutionState state) {
        val currentClientInfo = ClientInfoHolder.getClientInfo();

        val conversationScope = state.getConversationScope();
        val userAgent = (String) conversationScope.get(WEBFLOW_USER_AGENT);
        val clientIpAddress = (String) conversationScope.get(WEBFLOW_CLIENT_IP_ADDRESS);
        Assert.hasText(userAgent, "User-agent cannot be null or empty");
        Assert.hasText(clientIpAddress, "Client IP address cannot be null or empty");

        if (!Strings.CI.equals(currentClientInfo.getUserAgent(), userAgent)
            || !Strings.CI.equals(currentClientInfo.getClientIpAddress(), clientIpAddress)) {
            LOGGER.error("User-agent attached to the webflow [{}] does not match the current user-agent [{}] or "
                    + "client IP address attached to the webflow [{}] does not match the current client IP address [{}]. "
                    + "The flow execution key is invalid or likely tampered with.",
                userAgent, currentClientInfo.getUserAgent(), clientIpAddress, currentClientInfo.getClientIpAddress());
            throw new ClientFlowExecutionRepositoryException("Webflow execution key is invalid");
        }
    }


    @Getter
    public static class SerializedFlowExecutionState implements Serializable {
        @Serial
        private static final long serialVersionUID = -4020991769174829876L;

        private final String flowId;

        private final MutableAttributeMap conversationScope;

        private final FlowExecution execution;

        SerializedFlowExecutionState(final FlowExecution execution) {
            this.execution = execution;
            this.flowId = execution.getDefinition().getId();

View on GitHub (pinned to e7288fc434)