flowable/flowable-engine · warning
Invalid attribute value for 'activityRef': no activity with…
Error message
Invalid attribute value for 'activityRef': no activity with id '{}' in current scope {} What it means
During BPMN XML parsing, a compensate event definition specifies an activityRef whose id does not resolve to any activity in the current scope. Flowable (Activiti 5 compatibility engine) logs this warning instead of failing the parse; the compensateEventDefinition is still created, but the compensation target will not resolve at runtime. It signals a broken or misplaced compensation reference in the process model.
Solutions
- Fix the activityRef attribute in the BPMN XML to match the id of an activity in the same scope
- Remove the activityRef attribute to broadcast compensation to all activities in scope instead of one target
- Verify the referenced element exists in the same subprocess/transaction scope and re-deploy the process definition
Example fix
// before <intermediateThrowEvent id="comp"><compensateEventDefinition activityRef="taskOld" /></intermediateThrowEvent> // after <intermediateThrowEvent id="comp"><compensateEventDefinition activityRef="taskRenamed" /></intermediateThrowEvent>
Defensive patterns
Strategy: validation
Validate before calling
// pre-deploy check
for (EventDefinition ed : collectCompensateEventDefinitions(bpmnModel)) {
String ref = ed.getActivityRef();
if (ref != null && bpmnModel.getFlowElement(ref, true) == null) {
throw new IllegalArgumentException("activityRef '" + ref + "' not found in model");
}
} Type guard
function hasValidActivityRef(model, ref) { return typeof ref === 'string' && ref.length > 0 && model.getFlowElement(ref, true) != null; } Prevention
- Keep element ids stable; use modeler refactor/rename so compensation refs update together
- Validate BPMN with the schema/engine validation API before deployment
- Keep compensation targets in the same subprocess scope as the compensate event
When it happens
Trigger: executeParse of a CompensateEventDefinition when StringUtils.isNotEmpty(activityRef) and scope.findActivity(activityRef) returns null — i.e. the referenced id is misspelled, lives in a different (sub)process scope, or the element was removed.
Common situations: Hand-edited or generated BPMN XML with a stale activityRef; refactoring element ids in the modeler without updating the compensation boundary event; referencing an activity inside a nested subprocess from an outer-scope compensate event.
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
- Cannot start process instance. Process model (id = " +…
- Process model for could not be found
- Process model (id = ) could not be found for
- Activity needed for multi instance cannot bv found
- Cannot start process instance. Process definition
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/d97892f1aee5caf1.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/bpmn/parser/handler/CompensateEventDefinitionParseHandler.java:44
/**
* @author Joram Barrez
*/
public class CompensateEventDefinitionParseHandler extends AbstractBpmnParseHandler<CompensateEventDefinition> {
private static final Logger LOGGER = LoggerFactory.getLogger(CompensateEventDefinitionParseHandler.class);
@Override
public Class<? extends BaseElement> getHandledType() {
return CompensateEventDefinition.class;
}
@Override
protected void executeParse(BpmnParse bpmnParse, CompensateEventDefinition eventDefinition) {
ScopeImpl scope = bpmnParse.getCurrentScope();
if (StringUtils.isNotEmpty(eventDefinition.getActivityRef())) {
if (scope.findActivity(eventDefinition.getActivityRef()) == null) {
LOGGER.warn("Invalid attribute value for 'activityRef': no activity with id '{}' in current scope {}", eventDefinition.getActivityRef(), scope.getId());
}
}
org.activiti.engine.impl.bpmn.parser.CompensateEventDefinition compensateEventDefinition = new org.activiti.engine.impl.bpmn.parser.CompensateEventDefinition();
compensateEventDefinition.setActivityRef(eventDefinition.getActivityRef());
compensateEventDefinition.setWaitForCompletion(eventDefinition.isWaitForCompletion());
ActivityImpl activity = bpmnParse.getCurrentActivity();
if (bpmnParse.getCurrentFlowElement() instanceof ThrowEvent) {
activity.setActivityBehavior(bpmnParse.getActivityBehaviorFactory().createIntermediateThrowCompensationEventActivityBehavior((ThrowEvent) bpmnParse.getCurrentFlowElement(), compensateEventDefinition));
} else if (bpmnParse.getCurrentFlowElement() instanceof BoundaryEvent) {
BoundaryEvent boundaryEvent = (BoundaryEvent) bpmnParse.getCurrentFlowElement();
boolean interrupting = boundaryEvent.isCancelActivity();
activity.setActivityBehavior(bpmnParse.getActivityBehaviorFactory().createBoundaryEventActivityBehavior(boundaryEvent, interrupting, activity));View on GitHub (pinned to d6d39ce1c6)