stanfordnlp/CoreNLP · critical · IOException

Could not start a local server!

Error message

Could not start a local server!

What it means

WebServiceAnnotator.ensureServer attempts to launch the external annotator's local server process via startCommand/startServer. If startServer reports the process failed to start (non-null command but startServer returned false), it throws this IOException before any annotation request is made.

Solutions

  1. Run the configured start command manually and fix whatever makes it fail (missing binary, bad flags, missing runtime)
  2. Verify the port in the start command matches the annotator's configured target port and is free
  3. Check process logs/stderr — ensure the server actually binds and stays alive before the client gives up
  4. If the server is already running elsewhere, remove the start command so ensureServer skips local launch

Example fix

// before
props.setProperty("webservice.command", "/opt/annotators/missing-server.sh --port 8140");
// after
props.setProperty("webservice.command", "/opt/annotators/server.sh --port 8140"); // ensure file exists and is executable
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: verify the start command exists and the port is free
String cmd = props.getProperty("webservice.command");
if (cmd != null) {
  String bin = cmd.split("\\s+")[0];
  if (!new java.io.File(bin).canExecute())
    throw new IllegalStateException("Start command not executable: " + bin);
  int port = Integer.parseInt(props.getProperty("webservice.port", "8140"));
  try (var s = new java.net.ServerSocket(port)) { /* free */ }
  catch (java.io.IOException e) { throw new IllegalStateException("Port " + port + " already in use"); }
}

Try / catch

try {
  pipeline.annotate(doc);
} catch (java.io.IOException e) {
  if (e.getMessage().contains("Could not start a local server")) {
    log.error("Start command failed: run it manually and fix startup errors");
  }
  throw e;
}

Prevention

When it happens

Trigger: The web service annotator is configured with a start command (e.g. a script or 'docker run ...') that exits immediately or fails to bind its port — such as a missing binary, wrong path, or a port already in use.

Common situations: Deploying to a machine without the external service installed, bad executable path in the start command, insufficient permissions to execute the script, or container runtime missing.

Related errors


AI-assisted analysis of stanfordnlp/CoreNLP@1b7edd19c4 (2026-09-10). Data as JSON: /api/errors/e4cd045c560e332a. Report an issue: GitHub.

Appendix: source

Thrown at src/edu/stanford/nlp/pipeline/WebServiceAnnotator.java:255

   * This is certainly called from {@link #annotate(Annotation)}, but can also
   * be called from the constructor of the annotator to cache startup times.
   *
   * @throws TimeoutException Thrown if we could not connect to the server for the timeout period.
   * @throws IOException Thrown if we could not start the server process.
   */
  protected void ensureServer() throws TimeoutException, IOException {
    long startTime = System.currentTimeMillis();

    // if the server was active last time we checked, see if the server is still active
    if (serverWasActive) {
      if (ready(false))
        return;
    }

    // 1. Start a server, if applicable
    boolean serverStarted = startCommand().map(this::startServer).orElse(true);
    if (!serverStarted) {
      throw new IOException("Could not start a local server!");
    }

    // 2. Wait for the target server to come online
    while (!everLive) {
      if (System.currentTimeMillis() > startTime + CONNECT_TIMEOUT) {
        throw new TimeoutException("Could not connect to annotator: " + this);
      }
      if (!live()) {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException ignored) {}
      } else {
        everLive = true;
      }
    }
    log.info("Got liveness from server for " + this);

    // 3. Wait for the target server to become ready

View on GitHub (pinned to 1b7edd19c4)