flowable/flowable-engine · error · FlowableException
${sequenceFlowId} does not match a sequence flow for ${deleg
Error message
${sequenceFlowId} does not match a sequence flow for ${delegateExecution} What it means
DelegateHelper.leaveDelegate() resolves the execution's currentFlowElement as a sequenceFlowId from the BPMN model of the process definition. If the looked-up FlowElement is not a SequenceFlow (or is missing), Flowable throws this error, because it can only take outgoing flows when positioned on a sequence flow.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/delegate/DelegateHelper.java:63
/**
* To be used in an {@link ActivityBehavior} or {@link JavaDelegate}: leaves according to the default BPMN 2.0 rules: all sequenceflow with a condition that evaluates to true are followed.
*/
public static void leaveDelegate(DelegateExecution delegateExecution) {
CommandContextUtil.getAgenda().planTakeOutgoingSequenceFlowsOperation((ExecutionEntity) delegateExecution, true);
}
/**
* To be used in an {@link ActivityBehavior} or {@link JavaDelegate}: leaves the current activity via one specific sequenceflow.
*/
public static void leaveDelegate(DelegateExecution delegateExecution, String sequenceFlowId) {
String processDefinitionId = delegateExecution.getProcessDefinitionId();
org.flowable.bpmn.model.Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
FlowElement flowElement = process.getFlowElement(sequenceFlowId);
if (flowElement instanceof SequenceFlow) {
delegateExecution.setCurrentFlowElement(flowElement);
CommandContextUtil.getAgenda().planTakeOutgoingSequenceFlowsOperation((ExecutionEntity) delegateExecution, false);
} else {
throw new FlowableException(sequenceFlowId + " does not match a sequence flow for " + delegateExecution);
}
}
/**
* Returns the {@link BpmnModel} matching the process definition bpmn model for the process definition of the passed {@link DelegateExecution}.
*/
public static BpmnModel getBpmnModel(DelegateExecution execution) {
if (execution == null) {
throw new FlowableException("Null execution passed");
}
return ProcessDefinitionUtil.getBpmnModel(execution.getProcessDefinitionId());
}
/**
* Returns the current {@link FlowElement} where the {@link DelegateExecution} is currently at.
*/
public static FlowElement getFlowElement(DelegateExecution execution) {
BpmnModel bpmnModel = getBpmnModel(execution);View on GitHub (pinned to d6d39ce1c6)
Solutions
- Only invoke leaveDelegate when the execution is on a SequenceFlow (e.g. an execution listener attached to the sequence flow element)
- Check the currentFlowElement id exists in the current process definition's BPMN model before calling
- For logic on a node, use the appropriate agenda operation (planTakeOutgoingSequenceFlowsOperation on the activity) or DelegateHelper methods meant for flow elements
- Redeploy consistent model versions so running instances match the deployed definitions
Example fix
// before
public void execute(DelegateExecution execution) {
DelegateHelper.leaveDelegate(execution); // executed on a ServiceTask
}
// after: attach to the sequence flow, or guard
FlowElement el = execution.getCurrentFlowElement();
if (el instanceof SequenceFlow) {
DelegateHelper.leaveDelegate(execution);
} Defensive patterns
Strategy: type-guard
Validate before calling
FlowElement el = execution.getCurrentFlowElement();
boolean isSequenceFlow = el != null && el.getId() != null
&& ProcessDefinitionUtil.getProcessDefinition(execution.getProcessDefinitionId()) != null
&& DelegateHelper.getBpmnModel(execution).getMainProcess().getFlowElement(el.getId()) instanceof SequenceFlow; Type guard
boolean canLeaveDelegate(DelegateExecution e) {
FlowElement el = e.getCurrentFlowElement();
return el instanceof SequenceFlow;
} Try / catch
try {
DelegateHelper.leaveDelegate(execution);
} catch (FlowableException e) {
if (e.getMessage().contains("does not match a sequence flow")) {
// wrong element type: route logic to the appropriate node/flow listener
} else throw e;
} Prevention
- Attach leaveDelegate-style logic only to sequence-flow execution listeners
- Keep flow element ids stable across model versions, or redeploy matching versions together
When it happens
Trigger: Calling DelegateHelper.leaveDelegate(delegateExecution) while the delegate execution's currentFlowElement id (sequenceFlowId) does not exist in the process definition, or points to a different element type (task, event, gateway).
Common situations: Executing leaveDelegate from a listener/execution-logic attached to a node rather than to a sequence flow; changing the BPMN XML (renaming/removing the flow id) while old deployed process instances still run with cached state; copying delegate code between process models.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Null execution passed
- BPMN XSD could not be found
- The bpmn 2.0 xml is not properly encoded
- ${className} does not implement the ${CmmnTriggerableActivit
- ${className} does not implement the ${CmmnActivityBehavior.c
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/07dfa717ff6b0a3b.
Report an issue: GitHub.