SonarSource/sonarqube · error · IllegalStateException

Already started

Error message

Already started

What it means

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.

Source

Thrown at server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java:75

    this.stopWatcher = createStopWatcher(commands, this);
    this.hardStopWatcher = createHardStopWatcher(commands, this);
    this.runtime = runtime;
  }

  public ProcessCommands getCommands() {
    return commands;
  }

  public Props getProps() {
    return props;
  }

  /**
   * Launch process and waits until it's down
   */
  public void launch(Monitored mp) {
    if (!lifecycle.tryToMoveTo(Lifecycle.State.STARTING)) {
      throw new IllegalStateException("Already started");
    }
    monitored = mp;

    Logger logger = LoggerFactory.getLogger(getClass());
    try {
      launch(logger);
    } catch (Exception e) {
      logger.warn("Fail to start {}", processId.getHumanReadableName(), e);
      hardStop();
    }
  }

  private void launch(Logger logger) throws InterruptedException {
    logger.info("Starting {}", processId.getHumanReadableName());
    runtime.addShutdownHook(new Thread(() -> {
      exit.setInShutdownHook();
      stop();
    }));

View on GitHub (pinned to 184c821202)

Solutions

  1. Create a new ProcessEntryPoint instance for each launch
  2. Ensure launch is called only once per JVM/process
  3. Check the lifecycle state before calling launch
  4. Refactor tests to instantiate a fresh entry point per test

Example fix

// before
ProcessEntryPoint entry = ProcessEntryPoint.create(props);
entry.launch(monitored);
entry.launch(monitored); // throws
// after
ProcessEntryPoint entry = ProcessEntryPoint.create(props);
entry.launch(monitored); // single launch per instance
Defensive patterns

Strategy: validation

Validate before calling

if (lifecycle.getState() != Lifecycle.State.INIT) {
  throw new IllegalStateException("ProcessEntryPoint already launched");
}

Try / catch

try {
  entryPoint.launch(monitored);
} catch (IllegalStateException e) {
  if ("Already started".equals(e.getMessage())) { LOGGER.warn("launch called twice; ignoring"); } else throw e;
}

Prevention

When it happens

Trigger: Calling launch(monitor) twice on the same ProcessEntryPoint instance, or reusing a shutdown/restarted lifecycle.

Common situations: Testing code calling launch repeatedly on a shared entry point; wrapper scripts relaunching in the same JVM; accidental double invocation in main.

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 SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/4d2159abade15e48. Report an issue: GitHub.