apache/pulsar · error · RuntimeException

No free port found

Error message

No free port found

What it means

FunctionCommon.findAvailablePort asks the OS for an ephemeral port by opening a ServerSocket on port 0 and returning its local port. If binding a server socket fails with an IOException (e.g. the OS has exhausted ephemeral ports or sockets cannot be created), this RuntimeException wrapping the IOException is thrown. It means no free port could be obtained, not that a specific port was taken.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionCommon.java:83

/**
 * Utils used for runtime.
 */
@CustomLog
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class FunctionCommon {

    public static int findAvailablePort() {
        // The logic here is a little flaky. There is no guarantee that this
        // port returned will be available later on when the instance starts
        // TODO:- Fix this.
        try {
            ServerSocket socket = new ServerSocket(0);
            int port = socket.getLocalPort();
            socket.close();
            return port;
        } catch (IOException ex) {
            throw new RuntimeException("No free port found", ex);
        }
    }

    public static TypeDefinition[] getFunctionTypes(FunctionConfig functionConfig, TypePool typePool)
            throws ClassNotFoundException {
        return getFunctionTypes(functionConfig, typePool.describe(functionConfig.getClassName()).resolve());
    }

    public static TypeDefinition[] getFunctionTypes(FunctionConfig functionConfig, TypeDefinition functionClass) {
        boolean isWindowConfigPresent = functionConfig.getWindowConfig() != null;
        return getFunctionTypes(functionClass, isWindowConfigPresent);
    }

    public static TypeDefinition[] getFunctionTypes(TypeDefinition userClass, boolean isWindowConfigPresent) {
        Class<?> classParent = getFunctionClassParent(userClass, isWindowConfigPresent);
        TypeList.Generic typeArgsList = resolveInterfaceTypeArguments(userClass, classParent);
        TypeDescription.Generic[] typeArgs = new TypeDescription.Generic[2];
        typeArgs[0] = typeArgsList.get(0);

View on GitHub (pinned to 820761864e)

Solutions

  1. Check and increase the ephemeral port range (Linux: net.ipv4.ip_local_port_range) and enable net.ipv4.tcp_tw_reuse
  2. Raise the file-descriptor limit (ulimit -n / nofile) for the process running the functions worker
  3. Reduce connection churn or restart services holding thousands of TIME_WAIT sockets
  4. Inspect the wrapped IOException cause to confirm whether it is EMFILE/ENFILE vs address-family issues

Example fix

// host tuning
// before
net.ipv4.ip_local_port_range = 1024 32767
// after
net.ipv4.ip_local_port_range = 1024 65535
sysctl -w net.ipv4.tcp_tw_reuse=1
Defensive patterns

Strategy: retry

Validate before calling

// No reliable pre-check exists; probe system health beforehand
long open = java.lang.management.ManagementFactory
    .getPlatformMBeanServer()
    .getAttribute(javax.management.ObjectName.getInstance("java.lang:type=OperatingSystem"), "OpenFileDescriptorCount") != null
    ? (Long) java.lang.management.ManagementFactory.getPlatformMBeanServer()
        .getAttribute(javax.management.ObjectName.getInstance("java.lang:type=OperatingSystem"), "OpenFileDescriptorCount") : 0;
long max = (Long) java.lang.management.ManagementFactory.getPlatformMBeanServer()
    .getAttribute(javax.management.ObjectName.getInstance("java.lang:type=OperatingSystem"), "MaxFileDescriptorCount");
if (open > max * 0.9) log.warn("File descriptors nearly exhausted (" + open + "/" + max + "), port allocation may fail");

Try / catch

int port;
try {
    port = FunctionCommon.findAvailablePort();
} catch (RuntimeException e) {
    if (e.getCause() instanceof IOException) {
        log.warn("Port probe failed, retrying after backoff", e);
        Thread.sleep(500);
        port = FunctionCommon.findAvailablePort(); // retry once or use fallback range
    } else throw e;
}

Prevention

When it happens

Trigger: Calling findAvailablePort() when new ServerSocket(0) throws IOException — typically ephemeral port exhaustion (net.ipv4.ip_local_port_range full, TIME_WAIT buildup), file-descriptor/ulimit limits, or a restrictive security policy blocking socket creation.

Common situations: Hosts running many functions/instances simultaneously with heavy churn of short-lived connections; containers with low ulimit -n; misconfigured TCP stacks after load tests; IPv4/IPv6 stack issues in restricted environments.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/dd17cae8ebd05fdd. Report an issue: GitHub.