floci-io/floci · error · RuntimeException

Could not find a free port

Error message

Could not find a free port

What it means

Thrown by PortAllocator.allocateAny when opening an ephemeral ServerSocket on port 0 fails with an IOException — the OS could not hand out an ephemeral port at all. This is not range exhaustion (no range involved); it means socket creation itself failed, and the original IOException is chained.

Solutions

  1. Check the chained exception for the underlying cause (e.g. 'Too many open files')
  2. Raise the process fd limit (ulimit -n 65536) or restart the emulator to release leaked fds
  3. Find and stop whatever is consuming all ephemeral ports or file descriptors (lsof / ss)
  4. Reduce parallelism of container launches in test runs

Example fix

# before: default limits in CI
# (fd exhaustion during parallel tests)

# after
ulimit -n 65536
./mvnw test
Defensive patterns

Strategy: fallback

Validate before calling

// health check for fd/ephemeral headroom before heavy allocation
long openFds = Files.list(Path.of("/proc/self/fd")).count();
if (openFds > 0.9 * fdLimit()) throw new IllegalStateException("fd exhaustion imminent");

Try / catch

try {
    return allocator.allocateAny();
} catch (RuntimeException e) {
    // inspect e.getCause(): 'Too many open files' -> raise ulimit / restart; else check policy
}

Prevention

When it happens

Trigger: File-descriptor exhaustion on the host (ulimit -n reached), unusual security managers or seccomp profiles blocking socket binds, or a heavily loaded host with no ephemeral ports free in the OS range.

Common situations: Long-running test suites leaking sockets/fds; containers run with very low fd limits; CI runners under heavy parallel load; SELinux/AppArmor restricting binds.

Related errors


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/ee54a2b69c772757. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/github/hectorvent/floci/core/common/docker/PortAllocator.java:79

            LOG.debugv("Released port {0}", String.valueOf(port));
        }
    }

    /**
     * Finds any free TCP port using ephemeral port allocation.
     * This is the fastest method when any port will do.
     *
     * @return a free port
     * @throws RuntimeException if no free port can be allocated
     */
    public int allocateAny() {
        try (ServerSocket socket = new ServerSocket(0)) {
            socket.setReuseAddress(true);
            int port = socket.getLocalPort();
            LOG.debugv("Allocated ephemeral port {0}", String.valueOf(port));
            return port;
        } catch (IOException e) {
            throw new RuntimeException("Could not find a free port", e);
        }
    }

    /**
     * Checks if a specific port is currently free.
     *
     * @param port the port to check
     * @return true if the port is available, false otherwise
     */
    public boolean isPortFree(int port) {
        try (ServerSocket socket = new ServerSocket(port)) {
            socket.setReuseAddress(true);
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}

View on GitHub (pinned to 62ff490619)