flowable/flowable-engine · error · FlowableException

No sub process execution found for cancel end event in ${exe

Error message

No sub process execution found for cancel end event in ${executionEntity}

What it means

Inside a transactional sub process, a cancel end event must execute within a scope whose execution tree leads to a sub-process (scope) parent execution. CancelEndEventActivityBehavior walks up the execution tree looking for that parent scope execution; if none is found, the cancel end event was not placed in a valid transactional sub process context and this FlowableException is thrown.

Source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/CancelEndEventActivityBehavior.java:69

        ExecutionEntity currentlyExaminedExecution = executionEntityManager.findById(executionEntity.getParentId());
        while (currentlyExaminedExecution != null && parentScopeExecution == null) {
            if (currentlyExaminedExecution.getCurrentFlowElement() instanceof SubProcess subProcess) {
                parentScopeExecution = currentlyExaminedExecution;
                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 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);
        }

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Move the cancel end event inside a <transaction id="..."> sub process element; cancel end events are only valid in transactional sub processes.
  2. If no compensation/rollback semantics are needed, replace the cancel end event with a plain none end event.
  3. Validate the BPMN model on deployment so the invalid placement is rejected before runtime.
  4. Re-check the process after refactoring that cancel/boundary cancel pairs remain within the same transaction sub process.

Example fix

// before: cancel end event in plain sub process
<subProcess id="sp"><endEvent id="end"><cancelEventDefinition/></endEvent></subProcess>
// after
<transaction id="tx"><endEvent id="end"><cancelEventDefinition/></endEvent></transaction>
Defensive patterns

Strategy: validation

Validate before calling

// static BPMN check before deployment
element.getElementsByTagNameNS("*", "cancelEventDefinition"); // ensure cancel end events only exist inside <transaction> elements

Try / catch

try { execution.signal(); }
catch (FlowableException e) { if (e.getMessage().startsWith("No sub process execution found")) { refactorModelToTransactionSubProcess(); } else { throw e; } }

Prevention

When it happens

Trigger: A cancel end event is executed while the enclosing activity's parent chain contains no scope execution for a transactional sub process — e.g. the cancel end event is placed at process (root) level, or inside a plain embedded sub process that is not a transaction sub process.

Common situations: Modeler mistake: using a cancel end event outside a <transaction> element; refactoring a transaction sub process into an embedded sub process while keeping the cancel end event; copy-pasting cancel events into ordinary processes.

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/edf32214b98c978b. Report an issue: GitHub.