{"record":{"id":"0dc00e9b87d8b993","repo":"apache/dolphinscheduler","slug":"internalthread-is-already-started","errorCode":null,"errorMessage":"\"InternalThread is already started\"","messagePattern":"\"InternalThread is already started\"","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/serial/WorkflowSerialCoordinator.java","lineNumber":83,"sourceCode":"    @Autowired\n    private SerialCommandPriorityHandler serialCommandPriorityHandler;\n\n    private volatile boolean flag = false;\n\n    private Thread internalThread;\n\n    private static final int DEFAULT_FETCH_SIZE = 1000;\n\n    private static final int DEFAULT_FETCH_INTERVAL_SECONDS = 5;\n\n    @Override\n    public synchronized void start() {\n        log.info(\"WorkflowSerialCoordinator starting...\");\n        if (flag) {\n            throw new IllegalStateException(\"WorkflowSerialCoordinator is already started\");\n        }\n        if (internalThread != null) {\n            throw new IllegalStateException(\"InternalThread is already started\");\n        }\n        flag = true;\n        internalThread = new BaseDaemonThread(this::doStart) {\n        };\n        internalThread.setName(\"WorkflowSerialCoordinator-Thread\");\n        internalThread.start();\n        log.info(\"WorkflowSerialCoordinator started...\");\n    }\n\n    private void doStart() {\n        while (flag) {\n            try {\n                final StopWatch workflowSerialCoordinatorRoundCost = StopWatch.createStarted();\n                final List<SerialCommandsGroup> serialCommandsGroups = fetchSerialCommands();\n                serialCommandsGroups.forEach(this::handleSerialCommand);\n                log.debug(\"WorkflowSerialCoordinator handled SerialCommandsGroup size: {}, cost: {}/ms \",\n                        serialCommandsGroups.size(),\n                        workflowSerialCoordinatorRoundCost.getDuration().toMillis());","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/apache/dolphinscheduler/blob/02eac45a1b6676e639fcbfb4be2243de5771b05d/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/serial/WorkflowSerialCoordinator.java#L65-L101","documentation":"Second guard in WorkflowSerialCoordinator.start(): if internalThread is already created, the coordinator's background thread was started and start() cannot run again. Distinct from the flag check to catch direct thread mutation.","triggerScenarios":"Repeated start() calls where the flag may have been reset but internalThread is non-null; double initialization of the coordinator.","commonSituations":"Same as double-start: duplicate lifecycle hooks, tests reusing an instance, manual restart attempts.","solutions":["Only start the coordinator once per process lifetime","Recreate the coordinator object instead of re-calling start()","Remove duplicate start invocations from lifecycle code","Reset internalThread=null only after a proper close()/stop()"],"exampleFix":"// before\ninternalThread = null; coordinator.start(); // restart attempt\n// after\ncoordinator.close();\nWorkflowSerialCoordinator fresh = new WorkflowSerialCoordinator(...);\nfresh.start();","handlingStrategy":"validation","validationCode":"if (coordinator.isStarted()) { log.warn(\"already started\"); return; }","typeGuard":null,"tryCatchPattern":"try { coordinator.start(); } catch (IllegalStateException e) { log.warn(\"start ignored: {}\", e.getMessage()); }","preventionTips":["Guard start calls with an isStarted flag","Perform proper stop()/close() before any restart","Don't null out internalThread manually"],"tags":["java","lifecycle","master"],"backgroundTag":"invalid-state-transition","analyzedSha":"02eac45a1b6676e639fcbfb4be2243de5771b05d","analyzedAt":"2026-09-06T17:43:00.555Z","contentChangedAt":"2026-09-06T17:43:00.555Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}