elastic/elasticsearch · error · GradleException

Failed to read {exclusionsFileAbsolutePath}

Error message

Failed to read {exclusionsFileAbsolutePath}

What it means

Thrown by DockerSupportService.getLinuxExclusionList() when reading the Docker exclusion list file fails. The file path is configured via the DOCKER_ON_LINUX_EXCLUSIONS_FILE parameter, set by DockerSupportPlugin to .ci/dockerOnLinuxExclusions relative to the settings directory. The file contains newline-separated Linux distribution IDs that should be excluded from Docker tasks. IOException is wrapped in GradleException.

Source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/docker/DockerSupportService.java:279

            return excluded;
        }

        return false;
    }

    private List<String> getLinuxExclusionList() {
        File exclusionsFile = getParameters().getExclusionsFile();

        if (exclusionsFile.exists()) {
            try {
                return Files.readAllLines(exclusionsFile.toPath())
                    .stream()
                    .map(String::trim)
                    .filter(line -> (line.isEmpty() || line.startsWith("#")) == false)
                    .collect(Collectors.toList());
            } catch (IOException e) {
                throw new GradleException("Failed to read " + exclusionsFile.getAbsolutePath(), e);
            }
        } else {
            return Collections.emptyList();
        }
    }

    // visible for testing
    static String deriveId(Map<String, String> values) {
        return values.get("ID") + "-" + values.get("VERSION_ID");
    }

    // visible for testing
    static Map<String, String> parseOsRelease(final List<String> osReleaseLines) {
        final Map<String, String> values = new HashMap<>();

        osReleaseLines.stream().map(String::trim).filter(line -> (line.isEmpty() || line.startsWith("#")) == false).forEach(line -> {
            final String[] parts = line.split("=", 2);
            final String key = parts[0];

View on GitHub (pinned to db6a809a66)

Solutions

  1. Check the file permissions and ownership: ls -la .ci/dockerOnLinuxExclusions.
  2. If the file is a broken symlink, recreate it from git: git checkout -- .ci/dockerOnLinuxExclusions.
  3. Verify the file is readable by the Gradle daemon process user: test -r .ci/dockerOnLinuxExclusions && echo readable.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight check on exclusions file
File exclusionsFile = new File(settingsDir, ".ci/dockerOnLinuxExclusions");
if (exclusionsFile.exists() && !exclusionsFile.canRead()) {
    throw new GradleException("Exclusions file exists but cannot be read: " + exclusionsFile);
}

Prevention

When it happens

Trigger: getLinuxExclusionList() is called (transitively from isExcludedOs()), the exclusions file exists (File.exists() returns true), but Files.readAllLines throws IOException. This can happen due to permission denied, the file being a broken symlink, or concurrent modification during read.

Common situations: The .ci/dockerOnLinuxExclusions file has restrictive permissions (e.g., 000 or owned by a different user). The file is a symlink pointing to a non-existent target (exists() follows symlinks and returns true for broken symlinks in some JVM versions). A CI agent has a corrupted checkout where the file is partially written.

Related errors


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