{"record":{"id":"7cbf15d6bdcd9d4d","repo":"elastic/elasticsearch","slug":"available-port-ranges-have-exceeded-range-from","errorCode":null,"errorMessage":"Available port ranges have exceeded Range from {} to {}","messagePattern":"Available port ranges have exceeded Range from (.+?) to (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/util/ports/AvailablePortAllocator.java","lineNumber":30,"sourceCode":"import org.gradle.internal.Pair;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class AvailablePortAllocator {\n    public static final int MIN_PRIVATE_PORT = 10300;\n    public static final int MAX_PRIVATE_PORT = 13300;\n    public static final int DEFAULT_RANGE_SIZE = 10;\n\n    private final List<ReservedPortRange> reservations = new ArrayList<ReservedPortRange>();\n\n    private ReservedPortRangeFactory portRangeFactory = new DefaultReservedPortRangeFactory();\n\n    protected Pair<Integer, Integer> getNextPortRange(int rangeNumber) {\n        int startPort = MIN_PRIVATE_PORT + (rangeNumber * DEFAULT_RANGE_SIZE);\n        int endPort = startPort + DEFAULT_RANGE_SIZE - 1;\n        if (endPort > MAX_PRIVATE_PORT) {\n            throw new IllegalStateException(\n                \"Available port ranges have exceeded Range from \" + MIN_PRIVATE_PORT + \" to \" + MAX_PRIVATE_PORT\n            );\n        }\n        return Pair.of(startPort, endPort);\n    }\n\n    public ReservedPortRange reservePortRange() {\n        Pair<Integer, Integer> portRange = getNextPortRange(reservations.size());\n        ReservedPortRange range = portRangeFactory.getReservedPortRange(portRange.getLeft(), portRange.getRight());\n        reservations.add(range);\n        return range;\n    }\n}\n","sourceCodeStart":12,"sourceCodeEnd":44,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/util/ports/AvailablePortAllocator.java#L12-L44","documentation":"AvailablePortAllocator hands out fixed-size (DEFAULT_RANGE_SIZE=10) port ranges starting at MIN_PRIVATE_PORT=10300. getNextPortRange computes startPort = 10300 + rangeNumber*10 and rejects any range whose endPort exceeds MAX_PRIVATE_PORT=13300. With 10-port ranges this caps the allocator at 300 concurrent reservations; exceeding it is treated as a leak/exhaustion defect, not a recoverable condition.","triggerScenarios":"reservePortRange() is called more than 300 times without releasing ranges (reservations list grows unboundedly), so getNextPortRange(reservations.size()) returns an endPort > 13300. Typical in test-heavy Gradle runs spawning many clusters.","commonSituations":"A Gradle test orchestration layer leaks ReservedPortRange objects (never releases them); a very large parallel test matrix allocates more than 300 concurrent ranges; long-lived daemon accumulating reservations across builds.","solutions":["Ensure every reservePortRange() has a matching release/close so reservations are reaped.","Reduce the number of concurrently running clusters in the test matrix, or stagger them so ranges are reused.","If the cap is genuinely too low for legitimate use, raise MAX_PRIVATE_PORT (and MIN if needed) in AvailablePortAllocator — but first confirm the leak is not the real bug."],"exampleFix":"// before: ranges never released; reservations.size() climbs past 300\nReservedPortRange r = allocator.reservePortRange();\n// ... used but never closed\n// after: try-with-resources or explicit release\ntry (ReservedPortRange r = allocator.reservePortRange()) {\n    // use r\n}","handlingStrategy":"validation","validationCode":"if (allocator.reservationCount() >= (AvailablePortAllocator.MAX_PRIVATE_PORT - AvailablePortAllocator.MIN_PRIVATE_PORT) / AvailablePortAllocator.DEFAULT_RANGE_SIZE) {\n    // drain or refuse new reservations before calling reservePortRange()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always release ReservedPortRange objects (try-with-resources or explicit close).","Bound the number of concurrently running clusters in the test matrix.","Restart long-lived daemons periodically or track reservation growth."],"tags":["build","ports","resource-exhaustion","test-infra"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}