flowable/flowable-engine · error · FlowableException

Expected an activity behavior in flow node

Error message

Expected an activity behavior in flow node ${flowNode.getId()} for ${execution}

What it means

During a synchronous multi-instance continuation, ContinueProcessOperation requires the flow node to have an attached activity behavior that can be executed. If a FlowNode reaches this multi-instance path without behavior, the engine cannot continue and throws FlowableException with the node id and execution.

Solutions

  1. Check the node id in the message against the deployed model and confirm the element type is a supported Flowable task/node
  2. Ensure all BpmnParseHandler/extension modules used at design time are on the runtime classpath
  3. Redeploy the process definition after fixing the model or upgrading the engine
  4. If multi-instance is unnecessary, remove the multiInstanceLoopCharacteristics

Example fix

// before (bpmn)
<serviceTask id="step1" flowable:multiInstanceLoopCharacteristics="..." />
<!-- no class/delegateExpression binding -->
// after (bpmn)
<serviceTask id="step1" flowable:class="com.acme.Step1Delegate"
    flowable:multiInstanceLoopCharacteristics="..." />
Defensive patterns

Strategy: try-catch

Validate before calling

FlowNode node = (FlowNode) bpmnModel.getFlowElement(nodeId);
if (node.getBehavior() == null) {
    throw new IllegalStateException("Node " + nodeId + " has no activity behavior; check parse handlers");
}

Try / catch

try {
    // continuation happens inside engine ops
} catch (FlowableException e) {
    if (e.getMessage().contains("Expected an activity behavior")) {
        log.error("Model/parse problem at node; check deployed BPMN and parse handlers");
    }
    throw e;
}

Prevention

When it happens

Trigger: continueThroughFlowNode -> executeMultiInstanceSynchronous on a multi-instance flow node whose behavior is null — usually a custom/unknown element type, a listener-swallowed parse error, or a model element unsupported by the deployed BpmnParseHandler set.

Common situations: Custom BPMN extensions/parse handlers missing on the classpath; process XML deployed with elements the engine version does not map to behaviors; corrupted parse after version upgrade.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at modules/flowable-engine/src/main/java/org/flowable/engine/impl/agenda/ContinueProcessOperation.java:235

        if (activityBehavior != null) {
            executeActivityBehavior(activityBehavior, flowNode);
            
            if (execution.isMultiInstanceRoot() && !execution.isDeleted() && !execution.isEnded()) {
                // Create any boundary events, sub process boundary events will be created from the activity behavior
                List<ExecutionEntity> boundaryEventExecutions = null;
                List<BoundaryEvent> boundaryEvents = null;
                if (!inCompensation && flowNode instanceof Activity) { // Only activities can have boundary events
                    boundaryEvents = ((Activity) flowNode).getBoundaryEvents();
                    if (CollectionUtil.isNotEmpty(boundaryEvents)) {
                        boundaryEventExecutions = createBoundaryEvents(boundaryEvents, execution);
                    }
                }
                
                executeBoundaryEvents(boundaryEventExecutions);
            }
            
        } else {
            throw new FlowableException("Expected an activity behavior in flow node " + flowNode.getId() + " for " + execution);
        }
    }
    
    protected boolean hasMultiInstanceRootExecution(ExecutionEntity execution, FlowNode flowNode) {
        ExecutionEntity currentExecution = execution.getParent();
        while (currentExecution != null) {
            if (currentExecution.isMultiInstanceRoot() && flowNode.getId().equals(currentExecution.getActivityId())) {
                return true;
            }
            currentExecution = currentExecution.getParent();
        }
        return false;
    }
    
    protected ExecutionEntity createMultiInstanceRootExecution(ExecutionEntity execution) {
        ExecutionEntity parentExecution = execution.getParent();
        FlowElement flowElement = execution.getCurrentFlowElement();
        

View on GitHub (pinned to d6d39ce1c6)