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

  1. Fix the activityRef attribute in the BPMN XML to match the id of an activity in the same scope
  2. Remove the activityRef attribute to broadcast compensation to all activities in scope instead of one target
  3. 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

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


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)