Activiti/Activiti · error · ActivitiException
No sub process execution found for cancel end event
Error message
No sub process execution found for cancel end event
What it means
Thrown by CancelEndEventActivityBehavior.execute when a cancel end event cannot find the enclosing sub-process scope execution it must cancel. The behavior walks up the execution tree looking for the scope that contains a transaction, and if it never finds a parent scope execution it fails. Cancel end events are only valid inside a transactional sub-process with a cancel boundary event.
Solutions
- Move the cancel end event inside a <transaction subProcess> that has a cancel boundary event attached.
- Validate the BPMN model (activiti-modeler/validation) so cancel events only appear in transaction sub-processes.
- Check the execution tree in ACT_RU_EXECUTION for missing/damaged scope executions; restart the instance from a known-good state.
- Replace the cancel end event with an error end event + error boundary if transactional rollback semantics are not required.
Example fix
<!-- before --> <subProcess id="sp"><endEvent id="e"><cancelEventDefinition/></endEvent></subProcess> <!-- after --> <transaction id="tx"><endEvent id="e"><cancelEventDefinition/></endEvent></transaction> <boundaryEvent id="cancelB" attachedToRef="tx"><cancelEventDefinition/></boundaryEvent>
Defensive patterns
Strategy: validation
Validate before calling
// At deploy time: validate cancel end events are only inside <transaction> sub-processes
if (!"transaction".equals(parentElement.getType())) {
throw new IllegalArgumentException("cancelEndEvent must be inside a transaction subProcess");
} Try / catch
try {
processEngine.getRuntimeService().signal(executionId);
} catch (ActivitiException e) {
if (e.getMessage().startsWith("No sub process execution found")) {
// model error: redeploy corrected definition
}
} Prevention
- Run BPMN model validation before every deployment.
- Only place cancel end events inside transaction sub-processes.
- Prefer error end events when rollback semantics are not needed.
When it happens
Trigger: A <cancelEndEvent> is reached but the execution tree has no parent scope execution matching the transaction sub-process — e.g. cancel end event placed outside a transaction sub-process or model/config corruption removed the scope execution.
Common situations: BPMN modeling mistake: cancel end event in a regular (non-transaction) sub-process or at process level; historic process instances with modified executions after a DB migration or manual cleanup between Activiti versions.
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
- completed() can only be called on a
- completing() can only be called on a
- Could not find cancel boundary event for cancel end event
- Programmatic error: sub process behaviour can only be…
- BPMN XSD could not be found
AI-assisted analysis of Activiti/Activiti@56435b1a97 (2026-09-09).
Data as JSON: /api/errors/1e6eba15ffafe833.
Report an issue: GitHub.
Appendix: source
Thrown at activiti-core/activiti-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/CancelEndEventActivityBehavior.java:68
ExecutionEntity currentlyExaminedExecution = executionEntityManager.findById(executionEntity.getParentId());
while (currentlyExaminedExecution != null && parentScopeExecution == null) {
if (currentlyExaminedExecution.getCurrentFlowElement() instanceof SubProcess) {
parentScopeExecution = currentlyExaminedExecution;
SubProcess subProcess = (SubProcess) currentlyExaminedExecution.getCurrentFlowElement();
if (subProcess.getLoopCharacteristics() != null) {
ExecutionEntity miExecution = parentScopeExecution.getParent();
FlowElement miElement = miExecution.getCurrentFlowElement();
if (miElement != null && miElement.getId().equals(subProcess.getId())) {
parentScopeExecution = miExecution;
}
}
} else {
currentlyExaminedExecution = executionEntityManager.findById(currentlyExaminedExecution.getParentId());
}
}
if (parentScopeExecution == null) {
throw new ActivitiException(
"No sub process execution found for cancel end event " + executionEntity.getCurrentActivityId()
);
}
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().getFirst() instanceof CancelEventDefinition
) {
cancelBoundaryEvent = boundaryEvent;
break;
}
}
}
View on GitHub (pinned to 56435b1a97)