{"record":{"id":"b8d17e91643bbc63","repo":"flowable/flowable-engine","slug":"compensation-boundary-catch-must-be-connected-to-e","errorCode":null,"errorMessage":"compensation boundary catch must be connected to element with isForCompensation=true","messagePattern":"compensation boundary catch must be connected to element with isForCompensation=true","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/handler/AbstractBpmnParseHandler.java","lineNumber":203,"sourceCode":"            // connected to a text annotation so skipping it\n            return;\n        }\n\n        ActivityImpl sourceActivity = parentScope.findActivity(association.getSourceRef());\n        ActivityImpl targetActivity = parentScope.findActivity(association.getTargetRef());\n\n        // an association may reference elements that are not parsed as activities (like for instance\n        // text annotations so do not throw an exception if sourceActivity or targetActivity are null)\n        // However, we make sure they reference 'something':\n        if (sourceActivity == null) {\n            // bpmnModel.addProblem(\"Invalid reference sourceRef '\" + association.getSourceRef() + \"' of association element \", association.getId());\n        } else if (targetActivity == null) {\n            // bpmnModel.addProblem(\"Invalid reference targetRef '\" + association.getTargetRef() + \"' of association element \", association.getId());\n        } else {\n            if (sourceActivity.getProperty(\"type\").equals(\"compensationBoundaryCatch\")) {\n                Object isForCompensation = targetActivity.getProperty(PROPERTYNAME_IS_FOR_COMPENSATION);\n                if (isForCompensation == null || !(Boolean) isForCompensation) {\n                    LOGGER.warn(\"compensation boundary catch must be connected to element with isForCompensation=true\");\n                } else {\n                    ActivityImpl compensatedActivity = sourceActivity.getParentActivity();\n                    compensatedActivity.setProperty(BpmnParse.PROPERTYNAME_COMPENSATION_HANDLER_ID, targetActivity.getId());\n                }\n            }\n        }\n    }\n\n    protected Map<String, Object> processDataObjects(BpmnParse bpmnParse, Collection<ValuedDataObject> dataObjects, ScopeImpl scope) {\n        Map<String, Object> variablesMap = new HashMap<>();\n        // convert data objects to process variables\n        if (dataObjects != null) {\n            for (ValuedDataObject dataObject : dataObjects) {\n                variablesMap.put(dataObject.getName(), dataObject.getValue());\n            }\n        }\n        return variablesMap;\n    }","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/flowable/flowable-engine/blob/d6d39ce1c69ff244f2d9dc6af756a9b95e865586/modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/handler/AbstractBpmnParseHandler.java#L185-L221","documentation":"createAssociation() warns when an association connects a compensation boundary catch to an activity whose isForCompensation flag is not true. Compensation handlers must be marked isForCompensation=\"true\"; otherwise the engine refuses to register it as the compensation handler and the association is ignored.","triggerScenarios":"An association whose source is a compensation boundary catch (type \"compensationBoundaryCatch\") targets an activity lacking PROPERTYNAME_IS_FOR_COMPENSATION=true; logged in AbstractBpmnParseHandler.createAssociation() called from processArtifacts.","commonSituations":"Modeling a compensation handler without setting isForCompensation=true on the target task/subprocess; importing BPMN from other tools that omit the attribute.","solutions":["Set isForCompensation=\"true\" on the activity targeted by the compensation association","Verify the association direction: source should be the compensation boundary catch, target the compensation handler","Re-model the compensation pattern so the handler activity is a dedicated compensation task"],"exampleFix":"// before\n<serviceTask id=\"undoTask\"/>\n<association sourceRef=\"compCatch\" targetRef=\"undoTask\"/>\n// after\n<serviceTask id=\"undoTask\" isForCompensation=\"true\"/>\n<association sourceRef=\"compCatch\" targetRef=\"undoTask\"/>","handlingStrategy":"validation","validationCode":"// Compensation targets must be marked isForCompensation\nfor (Association a : process.getArtifactsOfType(Association.class)) {\n    BaseElement target = process.getFlowElement(a.getTargetRef());\n    if (isCompensationBoundaryCatch(a.getSourceRef()) && !Boolean.TRUE.equals(isForCompensation(target)))\n        throw new IllegalArgumentException(\"Compensation handler must set isForCompensation=true: \" + a.getTargetRef());\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set isForCompensation=\"true\" on compensation handler activities","Use standard compensation modeling patterns from the docs"],"tags":["bpmn","compensation","association"],"backgroundTag":"invalid-argument-value","analyzedSha":"d6d39ce1c69ff244f2d9dc6af756a9b95e865586","analyzedAt":"2026-09-11T06:41:19.413Z","contentChangedAt":"2026-09-11T06:41:19.413Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}