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

  1. Give each outgoing transition a unique id on the activity, or pass null when an id is not needed.
  2. Fix the BPMN source so sequence flow ids are unique per source element.
  3. 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

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


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)