flowable/flowable-engine · error · PvmException
joining scope executions is not allowed
Error message
joining scope executions is not allowed
What it means
Flowable/Activiti's process model concurrency (parallel gateway / multi-instance) joins multiple incoming executions into one. When more than one incoming execution arrives and any of them is a scope execution (an execution that carries local variables/its own variable scope), the engine cannot merge them and throws this PvmException. This is an internal BPMN modeling constraint enforced at runtime during transition taking.
Solutions
- Redesign the BPMN model so parallel flows that converge pass through non-scope executions; end each branch with an end event inside its scope so the scope terminates before joining.
- Place a parallel gateway before the subprocess exit so the scope execution ends and a fresh non-scope execution continues to the joining gateway.
- If branches carry local variables, move those variables to a parent scope or copy them explicitly before the join.
- Upgrade/verify engine version: newer Flowable versions handle some scope joins; check release notes for gateway/scope join fixes.
Example fix
// before: branches out of embedded subprocesses converge directly on one parallel gateway <parallelGateway id="join"/> ... <sequenceFlow sourceRef="subprocess1" targetRef="join"/> // after: terminate each scope with an end event, then join <subprocess id="sub1"><endEvent id="sub1End"/>...</subprocess> <sequenceFlow sourceRef="sub1" targetRef="join"/>
Defensive patterns
Strategy: validation
Validate before calling
// Model check: ensure no join gateway directly follows an embedded subprocess/callActivity without an intervening end event
boolean joinsScopeExit = bpmnModel.getGateways().stream()
.anyMatch(g -> g.getIncomingFlows().stream()
.anyMatch(f -> isScopeCreatingActivity(bpmnModel, f.getSourceRef())));
if (joinsScopeExit) throw new ModelValidationException("parallel gateway joins scope executions"); Prevention
- Terminate subprocess branches with end events before converging on join gateways
- Validate BPMN models with the model's validation API at deployment time
- Keep local variables out of branch scopes that later merge, or copy them up beforehand
When it happens
Trigger: Calling takeAll with recyclableExecutions.size() > 1 where at least one incoming execution has isScope()==true; typically a parallel/inclusive gateway or merge activity whose incoming flows originate from scope-creating activities (e.g. embedded subprocess call activities or activities with local scoped executions).
Common situations: BPMN models where a parallel gateway joins flows coming out of embedded subprocesses or call activities; using an inclusive gateway to merge scope executions; models migrated from older engine versions that previously tolerated scope joins.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Could not find a FlowElement for activityId
- Could not find cancel boundary event for cancel end event
- Default sequence flow
- Invalid reference in boundary event. Make sure that the…
- joining scope executions is not allowed
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/fb7fd38ea4069b1e.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/persistence/entity/ExecutionEntity.java:553
childExecutions.add(childExecution);
childExecutions.addAll(childExecution.getAllChildExecutions());
}
return childExecutions;
}
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public void takeAll(List<PvmTransition> transitions, List<ActivityExecution> recyclableExecutions) {
fireActivityCompletedEvent();
transitions = new ArrayList<>(transitions);
recyclableExecutions = (recyclableExecutions != null ? new ArrayList<>(recyclableExecutions) : new ArrayList<>());
if (recyclableExecutions.size() > 1) {
for (ActivityExecution recyclableExecution : recyclableExecutions) {
if (((ExecutionEntity) recyclableExecution).isScope()) {
throw new PvmException("joining scope executions is not allowed");
}
}
}
ExecutionEntity concurrentRoot = ((isConcurrent && !isScope) ? getParent() : this);
List<ExecutionEntity> concurrentActiveExecutions = new ArrayList<>();
List<ExecutionEntity> concurrentInActiveExecutions = new ArrayList<>();
for (ExecutionEntity execution : concurrentRoot.getExecutions()) {
if (execution.isActive()) {
concurrentActiveExecutions.add(execution);
} else {
concurrentInActiveExecutions.add(execution);
}
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("transitions to take concurrent: {}", transitions);
LOGGER.debug("active concurrent executions: {}", concurrentActiveExecutions);View on GitHub (pinned to d6d39ce1c6)