alibaba/COLA · error · StateMachineException
Internal transition source state '%s' and target state '%s'
Error message
Internal transition source state '%s' and target state '%s' must be same.
What it means
TransitionImpl.verify() enforces that an INTERNAL transition (which runs its action without changing state) has the same source and target state. verify() is invoked from transit(), so attempting to fire an internal transition whose source differs from its target throws this StateMachineException.
Source
Thrown at cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/impl/TransitionImpl.java:121
}
@Override
public boolean equals(Object anObject){
if(anObject instanceof Transition){
Transition other = (Transition)anObject;
if(this.event.equals(other.getEvent())
&& this.source.equals(other.getSource())
&& this.target.equals(other.getTarget())){
return true;
}
}
return false;
}
@Override
public void verify() {
if(type== TransitionType.INTERNAL && source != target) {
throw new StateMachineException(String.format("Internal transition source state '%s' " +
"and target state '%s' must be same.", source, target));
}
}
}
View on GitHub (pinned to 352e1a8675)
Solutions
- Make source and target identical for internal transitions: internal().from(S).to(S).event(E)
- Use a normal (external/local) transition instead of internal if the state should actually change
- Split the transition into separate transitions per state if it was meant to apply to multiple source states
Example fix
// before .internal().from(STATE_A).to(STATE_B).event(EVENT_X) // throws on verify // after .internal().from(STATE_A).to(STATE_A).event(EVENT_X) // or external .from(A).to(B)
Defensive patterns
Strategy: validation
Validate before calling
// when building, enforce source.equals(target) for internal transitions
if (transitionType == INTERNAL && !source.equals(target)) {
throw new IllegalStateException("internal transition must have source == target");
} Try / catch
try {
sm.fireEvent(source, event, ctx);
} catch (StateMachineException e) {
if (e.getMessage().contains("must be same")) {
// fix the transition definition: internal() requires from == to
} else {
throw e;
}
} Prevention
- For internal() transitions always set from(x).to(x)
- Use external/local transitions when the state must change
- Unit-test every transition definition before deploying
- Avoid mechanical conversion of external transitions to internal without adjusting to()
When it happens
Trigger: Defining a transition with internal() type (or INTERNAL TransitionType) where from(s) and to(t) specify different states, then firing the event so transit() calls verify().
Common situations: Developers misusing internal transitions to model state changes while expecting the action to run without a state change; converting external transitions to internal without updating to().
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- ${transition} already Exist, you can not add another one
- The state machine with id [${machineId}] is already built, n
- There is no stateMachine instance for ${machineId}, please b
- Cannot fire event [${event}] on current state [${sourceState
- ${currentStateId} is not found, please check state machine
AI-assisted analysis of alibaba/COLA@352e1a8675 (2026-09-08).
Data as JSON: /api/errors/c7bc3a63363b7cf4.
Report an issue: GitHub.