flowable/flowable-engine · error · FlowableException
Could not find cancel boundary event for cancel end event in
Error message
Could not find cancel boundary event for cancel end event in ${executionEntity} What it means
After locating the parent scope execution for a cancel end event, CancelEndEventActivityBehavior searches that scope's flow element (the SubProcess) for a boundary event with a cancelEventDefinition. If the transaction sub process has no cancel boundary event attached, the cancel has nothing to target, so this FlowableException is thrown.
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/CancelEndEventActivityBehavior.java:86
if (parentScopeExecution == null) {
throw new FlowableException("No sub process execution found for cancel end event in " + executionEntity);
}
SubProcess subProcess = (SubProcess) parentScopeExecution.getCurrentFlowElement();
BoundaryEvent cancelBoundaryEvent = null;
if (CollectionUtil.isNotEmpty(subProcess.getBoundaryEvents())) {
for (BoundaryEvent boundaryEvent : subProcess.getBoundaryEvents()) {
if (CollectionUtil.isNotEmpty(boundaryEvent.getEventDefinitions()) &&
boundaryEvent.getEventDefinitions().get(0) instanceof CancelEventDefinition) {
cancelBoundaryEvent = boundaryEvent;
break;
}
}
}
if (cancelBoundaryEvent == null) {
throw new FlowableException("Could not find cancel boundary event for cancel end event in " + executionEntity);
}
ExecutionEntity newParentScopeExecution = null;
currentlyExaminedExecution = executionEntityManager.findById(parentScopeExecution.getParentId());
while (currentlyExaminedExecution != null && newParentScopeExecution == null) {
if (currentlyExaminedExecution.isScope()) {
newParentScopeExecution = currentlyExaminedExecution;
} else {
currentlyExaminedExecution = executionEntityManager.findById(currentlyExaminedExecution.getParentId());
}
}
if (newParentScopeExecution == null) {
throw new FlowableException("Programmatic error: no parent scope execution found for boundary event " + cancelBoundaryEvent.getId() + " for " + parentScopeExecution);
}
ScopeUtil.createCopyOfSubProcessExecutionForCompensation(parentScopeExecution);
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Attach a cancel boundary event to the transaction sub process: <boundaryEvent id="cancelBoundary" attachedToRef="tx"><cancelEventDefinition/></boundaryEvent>.
- If no cancellation handling is required, remove the cancel end event and use a normal end event instead.
- Ensure the boundary event's attachedToRef points at the transaction sub process id, not an inner activity.
- Validate the model at deployment time to catch cancel end/boundary mismatches early.
Example fix
// before: transaction sub process without cancel boundary event <transaction id="tx">...</transaction> // after <boundaryEvent id="cancelB" attachedToRef="tx"><cancelEventDefinition/></boundaryEvent>
Defensive patterns
Strategy: validation
Validate before calling
// assert every transaction sub process with a cancel end event has a matching boundary cancel
for (Element tx : txSubProcesses) {
boolean hasCancelEnd = hasChild(tx, "cancelEventDefinition");
boolean hasCancelBoundary = hasBoundaryCancelAttachedTo(tx.getAttribute("id"));
if (hasCancelEnd && !hasCancelBoundary) throw new IllegalStateException("tx " + tx.getAttribute("id") + " missing cancel boundary event");
} Try / catch
try { execution.signal(); }
catch (FlowableException e) { if (e.getMessage().startsWith("Could not find cancel boundary event")) { addCancelBoundaryAndRedeploy(); } else { throw e; } } Prevention
- Pair every cancel end event with a cancel boundary event on the transaction sub process.
- Check attachedToRef points at the transaction element.
- Model-validate in CI before deployment.
- Review model diffs that touch compensation/cancel elements.
When it happens
Trigger: A cancel end event fires inside a transaction sub process that has no boundary event of type <cancelEventDefinition/> attached — the sub process contains the cancel end event but no matching cancel boundary catch.
Common situations: Modeler added a cancel end event (to force rollback) but forgot to attach the cancel boundary event; the boundary event was deleted during refactoring; the boundary event is attached to a different element than the transaction sub process.
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
- No sub process execution found for cancel end event in ${exe
- Could not resolve key for: ${eventDefinitionKey} in ${execut
- Cannot propagate escalation '" + escalationName + "' with co
- Unbound boundary event execution prevents the sub process in
- baseUrl can not be null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/4094c19e09e7c620.
Report an issue: GitHub.