languagetool-org/languagetool · critical · PortBindingException

https_server_start_failed

Error message

https_server_start_failed

What it means

When HTTPSServer fails to bind its HTTPS listener to host:port because the port is already in use (java.net.BindException), it wraps the failure in a PortBindingException with the localized 'https_server_start_failed' message. It means the server could not start listening on the requested address.

Source

Thrown at languagetool-server/src/main/java/org/languagetool/server/HTTPSServer.java:81

      if (host == null) {
        server = HttpsServer.create(new InetSocketAddress(port), 0);
      } else {
        server = HttpsServer.create(new InetSocketAddress(host, port), 0);
      }
      SSLContext sslContext = getSslContext(config.getKeystore(), config.getKeyStorePassword());
      HttpsConfigurator configurator = getConfigurator(sslContext);
      ((HttpsServer)server).setHttpsConfigurator(configurator);
      RequestLimiter limiter = getRequestLimiterOrNull(config);
      ErrorRequestLimiter errorLimiter = getErrorRequestLimiterOrNull(config);
      executorService = getExecutorService(config);
      BlockingQueue<Runnable> workQueue = executorService.getQueue();
      httpHandler = new LanguageToolHttpHandler(config, allowedIps, runInternally, limiter, errorLimiter, workQueue, this);
      server.createContext("/", httpHandler);
      server.setExecutor(executorService);
    } catch (BindException e) {
      ResourceBundle messages = JLanguageTool.getMessageBundle();
      String message = Tools.i18n(messages, "https_server_start_failed", host, Integer.toString(port));
      throw new PortBindingException(message, e);
    } catch (Exception e) {
      ResourceBundle messages = JLanguageTool.getMessageBundle();
      String message = Tools.i18n(messages, "https_server_start_failed_unknown_reason", host, Integer.toString(port));
      throw new RuntimeException(message, e);
    }
  }

  private SSLContext getSslContext(File keyStoreFile, String passPhrase) {
    try (FileInputStream keyStoreStream = new FileInputStream(keyStoreFile)) {
      KeyStore keystore = KeyStore.getInstance("JKS");
      keystore.load(keyStoreStream, passPhrase.toCharArray());
      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
      kmf.init(keystore, passPhrase.toCharArray());
      TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
      tmf.init(keystore);
      SSLContext sslContext = SSLContext.getInstance("TLS");
      sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
      return sslContext;

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Find the process using the port (e.g. ss -ltnp | grep <port> or lsof -i :<port>) and stop it.
  2. Choose a different port via the server config (port settings).
  3. Kill a stale previous LanguageTool server instance.
  4. In containers, fix the host port mapping or use the port-range option to auto-pick a free port.

Example fix

// before
# server.properties: port 8081 already used
port = 8081
// after
# stop the conflicting process first, or pick a free port
port = 8082
Defensive patterns

Strategy: try-catch

Validate before calling

// check port availability before startup
try (ServerSocket s = new ServerSocket()) {
  s.bind(new InetSocketAddress(host, port));
} catch (IOException e) {
  throw new IllegalStateException("Port " + port + " already in use");
}

Try / catch

try {
  httpsServer = new HTTPSServer(config, false, host, allowedIps);
} catch (PortBindingException e) {
  log.error("HTTPS port {} in use, pick another port", config.getPort(), e);
  System.exit(1);
}

Prevention

When it happens

Trigger: Starting the HTTPS server on a port already occupied by another process (or another running LT instance); binding to an address not available on the machine.

Common situations: Two LT server instances started simultaneously; port already taken by nginx/apache or a leftover JVM; running in a container where the mapped port is claimed.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/cecec09d2852c1bb. Report an issue: GitHub.