elastic/elasticsearch · error · UncheckedIOException

Failed to download branches.json from: {}

Error message

Failed to download branches.json from: {}

What it means

Thrown by GlobalBuildInfoPlugin.getDevelopmentBranches() when downloading branches.json from an http(s) URL fails. The download is performed by HttpUtils.readHttpBytesWithRetry(location), which attempts the download and retries. If all attempts fail with IOException, it is wrapped in UncheckedIOException. This only occurs when branchesFileLocation starts with http:// or https://.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/info/GlobalBuildInfoPlugin.java:248

            } else {
                throw new GradleException(
                    "Gradle is running in offline mode, but branches.json location ["
                        + configuredBranchesFileLocation
                        + "] is an http(s) URL and no local branches.json was found at ["
                        + localBranchesFile
                        + "]. Either disable offline mode, set -P"
                        + BRANCHES_FILE_LOCATION_PROPERTY
                        + "=<local file path>, or create branches.json at the workspace root."
                );
            }
        }
        LOGGER.info("Reading branches.json from {}", branchesFileLocation);
        byte[] branchesBytes;
        if (isHttpLocation(branchesFileLocation)) {
            try {
                branchesBytes = HttpUtils.readHttpBytesWithRetry(branchesFileLocation);
            } catch (IOException e) {
                throw new UncheckedIOException("Failed to download branches.json from: " + branchesFileLocation, e);
            }
        } else {
            try {
                branchesBytes = Files.readAllBytes(new File(branchesFileLocation).toPath());
            } catch (IOException e) {
                throw new UncheckedIOException("Failed to read branches.json from: " + branchesFileLocation, e);
            }
        }

        var branchesFileParser = new BranchesFileParser(new ObjectMapper());
        return branchesFileParser.parse(branchesBytes);
    }

    private static boolean isHttpLocation(String branchesFileLocation) {
        return branchesFileLocation.startsWith("http://") || branchesFileLocation.startsWith("https://");
    }

    private void logGlobalBuildInfo(BuildParameterExtension buildParams) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Verify network connectivity: curl -I <branches.json URL>.
  2. If behind a proxy, configure Gradle's proxy settings in gradle.properties or pass -Dhttps.proxyHost/-Dhttps.proxyPort.
  3. Use a local file instead: -Pbranches.file.location=/path/to/branches.json.
  4. Switch to --offline mode and place branches.json at the workspace root.

Example fix

# before
./gradlew build  # tries to download from default URL, network blocked

# after (local file)
./gradlew build -Pbranches.file.location=/home/user/branches.json

# after (offline with local copy)
cp /shared/branches.json branches.json
./gradlew build --offline
Defensive patterns

Strategy: retry

Validate before calling

// Validate network connectivity before build
try {
    HttpUtils.readHttpBytesWithRetry(branchesFileLocation);
} catch (IOException e) {
    logger.warn("Cannot reach branches.json URL, falling back to local file");
    branchesFileLocation = new File(workspaceDir, "branches.json").getAbsolutePath();
}

Try / catch

try {
    branchesBytes = HttpUtils.readHttpBytesWithRetry(branchesFileLocation);
} catch (IOException e) {
    // Fallback to local file
    File local = new File(workspaceDir, "branches.json");
    if (local.exists()) {
        branchesBytes = Files.readAllBytes(local.toPath());
    } else {
        throw new UncheckedIOException("Failed to download and no local fallback", e);
    }
}

Prevention

When it happens

Trigger: branchesFileLocation is an http(s) URL (the default or set via -Pbranches.file.location=https://...). HttpUtils.readHttpBytesWithRetry exhausts retries and throws IOException. Causes include DNS resolution failure, connection refused, HTTP 404/500, read timeout, or TLS handshake failure.

Common situations: The build runs in an environment without internet access (but not in --offline mode, which has its own error path). The URL is wrong or the hosting server is down. A corporate proxy blocks the request. TLS certificate issues on the hosting endpoint.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/c0f0d79e85354bd8. Report an issue: GitHub.