flowable/flowable-engine · error · PvmException
activity ' ' has duplicate transition
Error message
activity '${id}' has duplicate transition '${transitionId}' What it means
PvmException thrown by ActivityImpl.createOutgoingTransition when a transition with the same non-null transitionId already exists on this activity. The activity maintains a namedOutgoingTransitions map for id-based lookup, which must stay unique per activity. Adding a second transition with the same id would corrupt that index.
Solutions
- Give each outgoing transition a unique id on the activity, or pass null when an id is not needed.
- Fix the BPMN source so sequence flow ids are unique per source element.
- Deduplicate transition definitions before building (e.g. in a model importer).
Example fix
// before
activity.createOutgoingTransition("flow1", null, "a");
activity.createOutgoingTransition("flow1", null, "b"); // duplicate
// after
activity.createOutgoingTransition("flow1", null, "a");
activity.createOutgoingTransition("flow2", null, "b"); Defensive patterns
Strategy: validation
Validate before calling
Set<String> usedIds = new HashSet<>();
if (!usedIds.add(transitionId)) {
throw new IllegalArgumentException("duplicate outgoing transition id '" + transitionId + "' on activity " + id);
}
activity.createOutgoingTransition(transitionId, skipExpression, destination); Try / catch
try {
activity.createOutgoingTransition(transitionId, null, dest);
} catch (PvmException e) {
if (e.getMessage() != null && e.getMessage().contains("duplicate transition")) {
// reuse or generate a unique id
activity.createOutgoingTransition(transitionId + "-" + UUID.randomUUID(), null, dest);
}
} Prevention
- Enforce unique sequence-flow ids per source element when importing BPMN.
- Pass null as transitionId when a named transition is not required.
- Validate BPMN ids for global uniqueness before deployment.
When it happens
Trigger: Calling activity.createOutgoingTransition("sameId", ...) twice (or the builder's transition(...) helper twice with the same id) on one activity.
Common situations: Duplicate transition ids in BPMN XML (e.g. two sequence flows from the same gateway/activity with the same id), or programmatic building that reuses ids across loops.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- duplicate activity id
- Cannot start process instance, initial activity where the…
- couldn't execute event listener :
- destination ' ' not found. (referenced from transition in '…
- destinationActivityId is null
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/f4786098ab134589.
Report an issue: GitHub.
Appendix: source
Thrown at modules/flowable5-engine/src/main/java/org/activiti/engine/impl/pvm/process/ActivityImpl.java:77
this.failedJobRetryTimeCycleValue = failedJobRetryTimeCycleValue;
}
public TransitionImpl createOutgoingTransition() {
return createOutgoingTransition(null);
}
public TransitionImpl createOutgoingTransition(String transitionId) {
return createOutgoingTransition(transitionId, null);
}
public TransitionImpl createOutgoingTransition(String transitionId, Expression skipExpression) {
TransitionImpl transition = new TransitionImpl(transitionId, skipExpression, processDefinition);
transition.setSource(this);
outgoingTransitions.add(transition);
if (transitionId != null) {
if (namedOutgoingTransitions.containsKey(transitionId)) {
throw new PvmException("activity '" + id + "' has duplicate transition '" + transitionId + "'");
}
namedOutgoingTransitions.put(transitionId, transition);
}
return transition;
}
@Override
public TransitionImpl findOutgoingTransition(String transitionId) {
return namedOutgoingTransitions.get(transitionId);
}
@Override
public String toString() {
return "Activity(" + id + ")";
}
public ActivityImpl getParentActivity() {View on GitHub (pinned to d6d39ce1c6)