alibaba/COLA · error · StateMachineException
${transition} already Exist, you can not add another one
Error message
${transition} already Exist, you can not add another one What it means
EventTransitions stores transitions grouped by event. verify() is called from put() and throws this StateMachineException if an equal transition (same event, source, target) already exists, preventing silent overwrites/duplicates in the state machine definition.
Source
Thrown at cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/EventTransitions.java:45
transitions.add(transition);
eventTransitions.put(event, transitions);
}
else{
List existingTransitions = eventTransitions.get(event);
verify(existingTransitions, transition);
existingTransitions.add(transition);
}
}
/**
* Per one source and target state, there is only one transition is allowed
* @param existingTransitions
* @param newTransition
*/
private void verify(List<Transition<S,E,C>> existingTransitions, Transition<S,E,C> newTransition) {
for (Transition transition : existingTransitions) {
if (transition.equals(newTransition)) {
throw new StateMachineException(transition + " already Exist, you can not add another one");
}
}
}
public List<Transition<S,E,C>> get(E event){
return eventTransitions.get(event);
}
public List<Transition<S,E,C>> allTransitions(){
List<Transition<S,E,C>> allTransitions = new ArrayList<>();
for(List<Transition<S,E,C>> transitions : eventTransitions.values()){
allTransitions.addAll(transitions);
}
return allTransitions;
}
}
View on GitHub (pinned to 352e1a8675)
Solutions
- Remove the duplicate transition registration in the builder so each (event, source, target) is declared once
- If multiple targets are needed under one event, use conditions (when(...)) on distinct transitions rather than identical duplicates
- Review generated/merged state machine configs for duplicated edges before build
Example fix
// before .from(STATE_A).to(STATE_B) // in block 1 .from(STATE_A).to(STATE_B) // duplicate in block 2 -> throws // after .from(STATE_A).to(STATE_B).when(condition1) .from(STATE_A).to(STATE_C).when(condition2)
Defensive patterns
Strategy: validation
Validate before calling
// keep a Set of 'event|source|target' keys while building to detect duplicates
if (!transitionKeys.add(event + "|" + source + "|" + target)) {
throw new IllegalStateException("duplicate transition");
} Try / catch
try {
sm = builder.build(machineId);
} catch (StateMachineException e) {
if (e.getMessage().contains("already Exist")) {
// dedupe the builder configuration and rebuild
} else {
throw e;
}
} Prevention
- Declare each (event, source, target) transition exactly once
- Use conditions (when) for branching instead of duplicate edges
- Review generated/merged state machine configs for duplicate edges
- Centralize transition definitions to avoid copy-paste duplicates
When it happens
Trigger: Calling builder states().state(...).event(...).from(s).to(t) twice for the identical (event, source, target) triple, or programmatically adding a duplicate Transition via put().
Common situations: Copy-pasted builder blocks registering the same transition twice; merging two state machine definitions that both define the same transition; generated configuration duplicating edges.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- The state machine with id [${machineId}] is already built, n
- Internal transition source state '%s' and target state '%s'
- EXTENSION_DEFINE_DUPLICATE
- There is no stateMachine instance for ${machineId}, please b
- Cannot fire event [${event}] on current state [${sourceState
AI-assisted analysis of alibaba/COLA@352e1a8675 (2026-09-08).
Data as JSON: /api/errors/f9ba9701a129dd9a.
Report an issue: GitHub.