{"record":{"id":"4094c19e09e7c620","repo":"flowable/flowable-engine","slug":"could-not-find-cancel-boundary-event-for-cancel-en","errorCode":null,"errorMessage":"Could not find cancel boundary event for cancel end event in ${executionEntity}","messagePattern":"Could not find cancel boundary event for cancel end event in (.+?)","errorType":"exception","errorClass":"FlowableException","httpStatus":null,"severity":"error","filePath":"modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/CancelEndEventActivityBehavior.java","lineNumber":86,"sourceCode":"        if (parentScopeExecution == null) {\r\n            throw new FlowableException(\"No sub process execution found for cancel end event in \" + executionEntity);\r\n        }\r\n\r\n        SubProcess subProcess = (SubProcess) parentScopeExecution.getCurrentFlowElement();\r\n        BoundaryEvent cancelBoundaryEvent = null;\r\n        if (CollectionUtil.isNotEmpty(subProcess.getBoundaryEvents())) {\r\n            for (BoundaryEvent boundaryEvent : subProcess.getBoundaryEvents()) {\r\n                if (CollectionUtil.isNotEmpty(boundaryEvent.getEventDefinitions()) &&\r\n                        boundaryEvent.getEventDefinitions().get(0) instanceof CancelEventDefinition) {\r\n\r\n                    cancelBoundaryEvent = boundaryEvent;\r\n                    break;\r\n                }\r\n            }\r\n        }\r\n\r\n        if (cancelBoundaryEvent == null) {\r\n            throw new FlowableException(\"Could not find cancel boundary event for cancel end event in \" + executionEntity);\r\n        }\r\n\r\n        ExecutionEntity newParentScopeExecution = null;\r\n        currentlyExaminedExecution = executionEntityManager.findById(parentScopeExecution.getParentId());\r\n        while (currentlyExaminedExecution != null && newParentScopeExecution == null) {\r\n            if (currentlyExaminedExecution.isScope()) {\r\n                newParentScopeExecution = currentlyExaminedExecution;\r\n            } else {\r\n                currentlyExaminedExecution = executionEntityManager.findById(currentlyExaminedExecution.getParentId());\r\n            }\r\n        }\r\n\r\n        if (newParentScopeExecution == null) {\r\n            throw new FlowableException(\"Programmatic error: no parent scope execution found for boundary event \" + cancelBoundaryEvent.getId() + \" for \" + parentScopeExecution);\r\n        }\r\n\r\n        ScopeUtil.createCopyOfSubProcessExecutionForCompensation(parentScopeExecution);\r\n\r","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable-engine/src/main/java/org/flowable/engine/impl/bpmn/behavior/CancelEndEventActivityBehavior.java#L68-L104","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: transaction sub process without cancel boundary event\n<transaction id=\"tx\">...</transaction>\n// after\n<boundaryEvent id=\"cancelB\" attachedToRef=\"tx\"><cancelEventDefinition/></boundaryEvent>","handlingStrategy":"validation","validationCode":"// assert every transaction sub process with a cancel end event has a matching boundary cancel\nfor (Element tx : txSubProcesses) {\n  boolean hasCancelEnd = hasChild(tx, \"cancelEventDefinition\");\n  boolean hasCancelBoundary = hasBoundaryCancelAttachedTo(tx.getAttribute(\"id\"));\n  if (hasCancelEnd && !hasCancelBoundary) throw new IllegalStateException(\"tx \" + tx.getAttribute(\"id\") + \" missing cancel boundary event\");\n}","typeGuard":null,"tryCatchPattern":"try { execution.signal(); }\ncatch (FlowableException e) { if (e.getMessage().startsWith(\"Could not find cancel boundary event\")) { addCancelBoundaryAndRedeploy(); } else { throw e; } }","preventionTips":["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."],"tags":["flowable","cancel-end-event","boundary-event","transaction-subprocess"],"backgroundTag":"invalid-state-transition","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}