flowable/flowable-engine · error · FlowableException
No execution found for sub process of boundary cancel event
Error message
No execution found for sub process of boundary cancel event ${boundaryEvent.getId()} for ${execution} What it means
When a cancel boundary event on a transactional subprocess is triggered, BoundaryCancelEventActivityBehavior searches the execution tree for the subprocess's child execution. If no such child execution exists, the internal invariant of the transactional subprocess is broken, and the behavior throws FlowableException. This normally indicates an inconsistent execution tree (e.g. the subprocess scope already ended or the tree was manipulated externally).
Source
Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/BoundaryCancelEventActivityBehavior.java:60
BoundaryEvent boundaryEvent = (BoundaryEvent) execution.getCurrentFlowElement();
CommandContext commandContext = Context.getCommandContext();
ProcessEngineConfigurationImpl processEngineConfiguration = CommandContextUtil.getProcessEngineConfiguration(commandContext);
ExecutionEntityManager executionEntityManager = processEngineConfiguration.getExecutionEntityManager();
ExecutionEntity subProcessExecution = null;
// TODO: this can be optimized. A full search in the all executions shouldn't be needed
List<ExecutionEntity> processInstanceExecutions = executionEntityManager.findChildExecutionsByProcessInstanceId(execution.getProcessInstanceId());
for (ExecutionEntity childExecution : processInstanceExecutions) {
if (childExecution.getCurrentFlowElement() != null
&& childExecution.getCurrentFlowElement().getId().equals(boundaryEvent.getAttachedToRefId())) {
subProcessExecution = childExecution;
break;
}
}
if (subProcessExecution == null) {
throw new FlowableException("No execution found for sub process of boundary cancel event " + boundaryEvent.getId() + " for " + execution);
}
EventSubscriptionService eventSubscriptionService = processEngineConfiguration.getEventSubscriptionServiceConfiguration().getEventSubscriptionService();
List<CompensateEventSubscriptionEntity> eventSubscriptions = eventSubscriptionService.findCompensateEventSubscriptionsByExecutionId(subProcessExecution.getParentId());
if (!eventSubscriptions.isEmpty()) {
String deleteReason = DeleteReason.BOUNDARY_EVENT_INTERRUPTING + "(" + boundaryEvent.getId() + ")";
// cancel boundary is always sync
ScopeUtil.throwCompensationEvent(eventSubscriptions, execution, false);
executionEntityManager.deleteExecutionAndRelatedData(subProcessExecution, deleteReason, false);
if (subProcessExecution.getCurrentFlowElement() instanceof Activity activity) {
if (activity.getLoopCharacteristics() != null) {
ExecutionEntity miExecution = subProcessExecution.getParent();
List<ExecutionEntity> miChildExecutions = executionEntityManager.findChildExecutionsByParentExecutionId(miExecution.getId());
for (ExecutionEntity miChildExecution : miChildExecutions) {
if (!subProcessExecution.getId().equals(miChildExecution.getId()) && activity.getId().equals(miChildExecution.getCurrentActivityId())) {
View on GitHub (pinned to d6d39ce1c6)
Solutions
- Inspect ACT_RU_EXECUTION for the subprocess child executions; if rows were manually deleted, restore consistency by re-running the transaction or re-importing the process instance state.
- Cancel/complete the subprocess through supported APIs (rollback via the transaction, RuntimeService APIs) instead of direct DB manipulation.
- Reproduce the trigger sequence and guard against duplicate/late cancel signals (e.g. remove stale event subscriptions, avoid triggering the boundary event after the scope ended).
- If it occurs on a supported path, gather the execution-tree dump and report it as an engine bug (internal invariant violation).
Example fix
// before (external manipulation)
jdbcTemplate.update("delete from ACT_RU_EXECUTION where PARENT_ID_ = ?", subProcessExecutionId);
// after (use engine API to end the scope)
managementService.executeCommand(new DeleteScopeCommand(subProcessExecutionId)); // or let the transaction rollback handle it Defensive patterns
Strategy: try-catch
Validate before calling
boolean childExists = runtimeService.createExecutionQuery()
.processInstanceId(processInstanceId)
.activityId("transactionalSubProcessId")
.count() > 0;
if (!childExists) {
throw new IllegalStateException("Sub process scope already gone; cannot fire cancel boundary");
} Try / catch
try {
// engine-internal path; guard your own cancellation triggers
runtimeService.trigger(boundaryExecutionId);
} catch (FlowableException e) {
if (e.getMessage().startsWith("No execution found for sub process of boundary cancel event")) {
// execution tree inconsistent: audit DB changes / duplicate signals
} else {
throw e;
}
} Prevention
- Never modify ACT_RU_EXECUTION (or other runtime tables) directly outside engine APIs
- Avoid sending duplicate/late cancel signals to an already-terminated subprocess scope
- Let transaction rollback propagate cancellation through the engine instead of manual cleanup
- On unexplained occurrences, dump the execution tree and report as a possible engine bug
When it happens
Trigger: Cancelling a transaction subprocess (trigger() on the cancel boundary event / via transaction rollback propagation) when the subprocess's child execution is missing — e.g. the scope was already terminated, concurrent cancellation, or execution tree modified outside the engine APIs (direct DB edits, custom commands).
Common situations: Manually deleting/patching ACT_RU_EXECUTION rows; a custom JobHandler or command that removed the subprocess execution without destroying the boundary event subscription; racing cancel signals delivered twice; engine upgrades with legacy corrupted histories.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- The default BPMN parse handlers should only support one type
- The default BPMN parse handlers should only support one type
- BPMN XSD could not be found
- The bpmn 2.0 xml is not properly encoded
- Error while reading the BPMN 2.0 XML
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/bbc1a8c04f2c04ab.
Report an issue: GitHub.