apache/dolphinscheduler · error · IllegalStateException

"WorkflowSerialCoordinator is already started"

Error message

"WorkflowSerialCoordinator is already started"

What it means

WorkflowSerialCoordinator.start() is guarded so it can only be started once; calling it again when the started flag is set throws this IllegalStateException. This protects the single internal daemon thread that polls serial commands.

Solutions

  1. Ensure start() is invoked once per coordinator instance
  2. Check for duplicate bean initialization in Spring config/component scanning
  3. Create a new coordinator instance before restarting
  4. Guard calls with the coordinator's own lifecycle state

Example fix

// before
coordinator.start();
coordinator.start(); // throws
// after
if (!coordinator.isStarted()) coordinator.start();
Defensive patterns

Strategy: validation

Validate before calling

if (coordinatorStarted) { /* skip start */ } else { coordinator.start(); coordinatorStarted = true; }

Type guard

boolean canStart(WorkflowSerialCoordinator c) { return !c.isStarted() && !c.isClosed(); }

Try / catch

try { coordinator.start(); } catch (IllegalStateException e) { log.warn("coordinator already started: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling start() a second time on the same coordinator instance, e.g. duplicate lifecycle start from Spring context refresh or manual re-initialization.

Common situations: Misconfigured bean lifecycle causing double start, tests calling start() repeatedly without recreating the object.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of apache/dolphinscheduler@02eac45a1b (2026-09-06). Data as JSON: /api/errors/009fe91aa2063182. Report an issue: GitHub.

Appendix: source

Thrown at dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/serial/WorkflowSerialCoordinator.java:80

    @Autowired
    private SerialCommandDiscardHandler serialCommandDiscardHandler;

    @Autowired
    private SerialCommandPriorityHandler serialCommandPriorityHandler;

    private volatile boolean flag = false;

    private Thread internalThread;

    private static final int DEFAULT_FETCH_SIZE = 1000;

    private static final int DEFAULT_FETCH_INTERVAL_SECONDS = 5;

    @Override
    public synchronized void start() {
        log.info("WorkflowSerialCoordinator starting...");
        if (flag) {
            throw new IllegalStateException("WorkflowSerialCoordinator is already started");
        }
        if (internalThread != null) {
            throw new IllegalStateException("InternalThread is already started");
        }
        flag = true;
        internalThread = new BaseDaemonThread(this::doStart) {
        };
        internalThread.setName("WorkflowSerialCoordinator-Thread");
        internalThread.start();
        log.info("WorkflowSerialCoordinator started...");
    }

    private void doStart() {
        while (flag) {
            try {
                final StopWatch workflowSerialCoordinatorRoundCost = StopWatch.createStarted();
                final List<SerialCommandsGroup> serialCommandsGroups = fetchSerialCommands();
                serialCommandsGroups.forEach(this::handleSerialCommand);

View on GitHub (pinned to 02eac45a1b)