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
- Run the configured start command manually and fix whatever makes it fail (missing binary, bad flags, missing runtime)
- Verify the port in the start command matches the annotator's configured target port and is free
- Check process logs/stderr — ensure the server actually binds and stays alive before the client gives up
- 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
- Run the start command manually once before wiring it into the pipeline
- Check that the executable path exists and has execute permission
- Ensure the configured port is free and matches the server's bind port
- Capture and log the server process's stdout/stderr for diagnosis
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
- Could not connect to annotator:
- Never got readiness from annotator:
- Server is not ready and can not start it!
- Could not annotate document after 3 tries:
- process exited with value
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 readyView on GitHub (pinned to 1b7edd19c4)