alibaba/COLA · error · StateMachineException
The state machine with id [${machineId}] is already built, n
Error message
The state machine with id [${machineId}] is already built, no need to build again What it means
StateMachineFactory keeps a static registry of state machines keyed by machineId. register() throws this StateMachineException when a machine with the same id is already present in the map, to enforce one machine per id. It fires when the same machineId is built and registered twice.
Source
Thrown at cola-components/cola-component-statemachine/src/main/java/com/alibaba/cola/statemachine/StateMachineFactory.java:20
import com.alibaba.cola.statemachine.impl.StateMachineException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* StateMachineFactory
*
* @author Frank Zhang
* @date 2020-02-08 10:21 PM
*/
public class StateMachineFactory {
static Map<String /* machineId */, StateMachine> stateMachineMap = new ConcurrentHashMap<>();
public static <S, E, C> void register(StateMachine<S, E, C> stateMachine){
String machineId = stateMachine.getMachineId();
if(stateMachineMap.get(machineId) != null){
throw new StateMachineException("The state machine with id ["+machineId+"] is already built, no need to build again");
}
stateMachineMap.put(stateMachine.getMachineId(), stateMachine);
}
public static <S, E, C> StateMachine<S, E, C> get(String machineId){
StateMachine stateMachine = stateMachineMap.get(machineId);
if(stateMachine == null){
throw new StateMachineException("There is no stateMachine instance for "+machineId+", please build it first");
}
return stateMachine;
}
}
View on GitHub (pinned to 352e1a8675)
Solutions
- Use StateMachineFactory.get(machineId) first and only build/register when it returns null
- Use unique machineIds (e.g. append a timestamp/UUID) if multiple instances are intentional
- Guard initialization with a singleton/once flag so build code runs once per JVM
- In tests, build in a static initializer or check the factory cache before rebuilding
Example fix
// before
StateMachine<...> sm = builder.build("orderSM"); // second call throws
// after
StateMachine<...> sm = StateMachineFactory.get("orderSM");
if (sm == null) {
sm = builder.build("orderSM");
} Defensive patterns
Strategy: validation
Validate before calling
if (StateMachineFactory.get(machineId) != null) {
throw new IllegalStateException("machineId already registered: " + machineId);
} Try / catch
try {
StateMachineFactory.register(sm);
} catch (StateMachineException e) {
if (e.getMessage().contains("already built")) {
sm = StateMachineFactory.get(machineId); // reuse existing
} else {
throw e;
}
} Prevention
- Check StateMachineFactory.get(machineId) before building
- Use a constant or UUID-based machineId scheme
- Initialize state machines once (singleton/static init)
- In tests, reuse the factory cache across test methods
When it happens
Trigger: Calling StateMachineBuilder.builder(...) ... build(machineId) (or StateMachineFactory.register) twice with the same machineId, e.g. re-running initialization code on app restart within the same JVM or duplicate Spring bean creation.
Common situations: Hot-reload or repeated initialization of state machines in tests (multiple @BeforeAll building the same id); duplicate bean definitions; classloader re-loading in app servers.
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
- There is no stateMachine instance for ${machineId}, please b
- ${transition} already Exist, you can not add another one
- EXTENSION_DEFINE_DUPLICATE
- 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/8a17f0863062bc9e.
Report an issue: GitHub.