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

  1. Remove the duplicate transition registration in the builder so each (event, source, target) is declared once
  2. If multiple targets are needed under one event, use conditions (when(...)) on distinct transitions rather than identical duplicates
  3. 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

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


AI-assisted analysis of alibaba/COLA@352e1a8675 (2026-09-08). Data as JSON: /api/errors/f9ba9701a129dd9a. Report an issue: GitHub.