{"record":{"id":"4d2159abade15e48","repo":"SonarSource/sonarqube","slug":"already-started","errorCode":null,"errorMessage":"Already started","messagePattern":"Already started","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java","lineNumber":75,"sourceCode":"    this.stopWatcher = createStopWatcher(commands, this);\n    this.hardStopWatcher = createHardStopWatcher(commands, this);\n    this.runtime = runtime;\n  }\n\n  public ProcessCommands getCommands() {\n    return commands;\n  }\n\n  public Props getProps() {\n    return props;\n  }\n\n  /**\n   * Launch process and waits until it's down\n   */\n  public void launch(Monitored mp) {\n    if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) {\n      throw new IllegalStateException(\"Already started\");\n    }\n    monitored = mp;\n\n    Logger logger = LoggerFactory.getLogger(getClass());\n    try {\n      launch(logger);\n    } catch (Exception e) {\n      logger.warn(\"Fail to start {}\", processId.getHumanReadableName(), e);\n      hardStop();\n    }\n  }\n\n  private void launch(Logger logger) throws InterruptedException {\n    logger.info(\"Starting {}\", processId.getHumanReadableName());\n    runtime.addShutdownHook(new Thread(() -> {\n      exit.setInShutdownHook();\n      stop();\n    }));","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java#L57-L93","documentation":"ProcessEntryPoint.launch guards against double-startup by moving the lifecycle to STARTING atomically. If the process (or this entry point) is already started, the transition fails and IllegalStateException 'Already started' is thrown.","triggerScenarios":"Calling launch(monitor) twice on the same ProcessEntryPoint instance, or reusing a shutdown/restarted lifecycle.","commonSituations":"Testing code calling launch repeatedly on a shared entry point; wrapper scripts relaunching in the same JVM; accidental double invocation in main.","solutions":["Create a new ProcessEntryPoint instance for each launch","Ensure launch is called only once per JVM/process","Check the lifecycle state before calling launch","Refactor tests to instantiate a fresh entry point per test"],"exampleFix":"// before\nProcessEntryPoint entry = ProcessEntryPoint.create(props);\nentry.launch(monitored);\nentry.launch(monitored); // throws\n// after\nProcessEntryPoint entry = ProcessEntryPoint.create(props);\nentry.launch(monitored); // single launch per instance","handlingStrategy":"validation","validationCode":"if (lifecycle.getState() != Lifecycle.State.INIT) {\n  throw new IllegalStateException(\"ProcessEntryPoint already launched\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  entryPoint.launch(monitored);\n} catch (IllegalStateException e) {\n  if (\"Already started\".equals(e.getMessage())) { LOGGER.warn(\"launch called twice; ignoring\"); } else throw e;\n}","preventionTips":["Call launch exactly once per ProcessEntryPoint instance","Create a fresh instance for every restart","Guard shared entry points in tests with state flags"],"tags":["lifecycle","state","startup"],"backgroundTag":"invalid-state-transition","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}