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
- Restart the flow with a fresh execution key
- Check for clients whose user-agent or IP legitimately changes mid-flow (proxies, mobile handoff)
- Disable webflow session pinning (cas.webflow.session.pinToSession=false) if not required
- 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)