flowable/flowable-engine · error · ActivitiException
Could not find cancel boundary event for cancel end event
Error message
Could not find cancel boundary event for cancel end event ${activity} What it means
CancelEndEventActivityBehavior.execute() searches the activity's parent scopes for a cancel boundary event attached to the enclosing transaction subprocess. If none exists, the cancel end event was modeled outside a transaction subprocess with a compensating cancel boundary, so it throws ActivitiException.
Solutions
- Place the cancel end event inside a transaction subprocess and attach a cancel boundary event to that transaction
- Remove the cancel end event and use a plain end event if transaction rollback semantics are not intended
- Validate the BPMN model at deploy time to catch illegal cancel end event usage
Example fix
// before <subProcess id="sp"><endEvent id="cancelEnd"><cancelEventDefinition/></endEvent></subProcess> // after <transaction id="tx"> <endEvent id="cancelEnd"><cancelEventDefinition/></endEvent> </transaction> <boundaryEvent id="cancelBoundary" attachedToRef="tx"><cancelEventDefinition/></boundaryEvent>
Defensive patterns
Strategy: validation
Validate before calling
// Validate at model/deploy time: cancel end events must sit inside a transaction with a cancel boundary boolean valid = hasTransactionSubprocessWithCancelBoundary(activityId);
Try / catch
try { /* execute flow */ }
catch (ActivitiException e) { if (e.getMessage().contains("cancel boundary event")) { flagModelingError(); } throw e; } Prevention
- Only use cancel end events inside transaction subprocesses
- Always attach a cancel boundary event to the transaction
- Validate BPMN models before deployment
When it happens
Trigger: A cancel end event is placed inside a subprocess that is not a transaction subprocess, or the transaction subprocess has no cancel boundary event attached, and execution reaches the cancel end event.
Common situations: Mis-modeled BPMN: cancel end event used outside transaction/cancel-boundary context; a model copied from another diagram where the boundary event was deleted.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Could not find a FlowElement for activityId
- Default sequence flow
- end event with cancelEventDefinition only supported inside…
- joining scope executions is not allowed
- activity ' ' has duplicate transition
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/2565a08ed5729bf8.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/behavior/CancelEndEventActivityBehavior.java:38
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.runtime.InterpretableExecution;
import org.flowable.engine.delegate.DelegateExecution;
/**
* @author Daniel Meyer
* @author Falko Menge
*/
public class CancelEndEventActivityBehavior extends FlowNodeActivityBehavior {
@Override
public void execute(DelegateExecution execution) {
ActivityExecution activityExecution = (ActivityExecution) execution;
// find cancel boundary event:
ActivityImpl cancelBoundaryEvent = ScopeUtil
.findInParentScopesByBehaviorType((ActivityImpl) activityExecution.getActivity(), CancelBoundaryEventActivityBehavior.class);
if (cancelBoundaryEvent == null) {
throw new ActivitiException("Could not find cancel boundary event for cancel end event " + activityExecution.getActivity());
}
ActivityExecution scopeExecution = ScopeUtil.findScopeExecutionForScope((ExecutionEntity) execution, cancelBoundaryEvent.getParentActivity());
// end all executions and process instances in the scope of the transaction
scopeExecution.destroyScope("cancel end event fired");
// the scope execution executes the boundary event
InterpretableExecution outgoingExecution = (InterpretableExecution) scopeExecution;
outgoingExecution.setActivity(cancelBoundaryEvent);
outgoingExecution.setActive(true);
// execute the boundary
cancelBoundaryEvent
.getActivityBehavior()
.execute(outgoingExecution);
}
View on GitHub (pinned to d6d39ce1c6)