pentaho/pentaho-kettle · error · IOException

Server socket on port " + port + " is already in use by ["…

Error message

Server socket on port " + port + " is already in use by [" + entry.getUser() + "]

What it means

SocketRepository.openServerSocket manages the pool of TCP ports Carte allocates for clustered step data channels. If the port's entry already exists in socketMap and entry.isInUse() is true, it throws IOException("Server socket on port <port> is already in use by [<user>]") — the port is already reserved by another allocation (identified by its user, e.g. a clustered transformation). It is a local port-lease conflict, not necessarily an OS-level bind failure.

Solutions

  1. Identify the holder from the message ([user] names the owning run) and ensure that transformation releases its port; restart the stuck transformation or Carte.
  2. Give each cluster schema a distinct, non-overlapping port range (cluster schema 'Sockets buffer size'/port settings).
  3. Restart the Carte slave to clear the in-memory socketMap if entries are stale after a crash.
  4. Check with `lsof -i :<port>`/`netstat` whether an OS-level process still holds the port; kill it if orphaned.
  5. Use a wider port range so concurrent clustered runs don't collide.

Example fix

// before: two cluster schemas share a range
clusterSchemaA ports: 40000-40010
clusterSchemaB ports: 40000-40010

// after: disjoint ranges
clusterSchemaA ports: 40000-40010
clusterSchemaB ports: 40011-40020
Defensive patterns

Strategy: validation

Validate before calling

// ensure cluster schemas use disjoint port ranges before executing
Set<Interval> ranges = new HashSet<>();
for (ClusterSchema cs : clusterSchemas) {
  Interval r = cs.getSocketsPortRange();
  if (!ranges.add(r)) throw new IllegalStateException("overlapping port range: " + r);
}

Try / catch

try {
  int port = socketRepository.allocateServerSocketPort(clusterSchema, user);
} catch (IOException e) {
  if (e.getMessage().contains("already in use")) {
    log.warn("Port pool exhausted/contended; restarting stale runs or widening range");
    // free the holder or widen the range, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: allocateServerSocketPort called for a port that a previous allocation never released (releaseSocket not called after a crashed transformation), or two cluster schemas/transformation runs configured with overlapping port ranges requesting the same port concurrently.

Common situations: Carte restarted improperly or slave transformations killed mid-run leaving entries marked in use; multiple cluster schemas on the same Carte configured with the same port range (e.g. 40000-40020); stale Carte process still holding the port.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/8dd5cfa887eac633. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/www/SocketRepository.java:110

  }

  public synchronized ServerSocket openServerSocket( int port, String user ) throws IOException {

    SocketRepositoryEntry entry = socketMap.get( port );
    if ( entry == null ) {

      ServerSocket serverSocket = createServerSocket( port );
      entry = new SocketRepositoryEntry( port, serverSocket, true, user );

      // Store the entry in the map too!
      //
      socketMap.put( port, entry );

    } else {
      // Verify that the socket is not in use...
      //
      if ( entry.isInUse() ) {
        throw new IOException( "Server socket on port " + port + " is already in use by [" + entry.getUser() + "]" );
      }
      if ( entry.getServerSocket().isClosed() ) {
        entry.setServerSocket( createServerSocket( port ) );
      }
      entry.setInUse( true );
    }

    return entry.getServerSocket();
  }

  /**
   * We don't actually ever close a server socket, we re-use them as much as possible.
   *
   * @param port
   * @throws IOException
   */
  public synchronized void releaseSocket( int port ) throws IOException {

View on GitHub (pinned to f3058517a1)