elastic/elasticsearch · error · GradleException

Failed to read /etc/os-release

Error message

Failed to read /etc/os-release

What it means

Thrown by DockerSupportService.isExcludedOs() when reading /etc/os-release fails with an IOException. The build reads /etc/os-release to determine the Linux distribution ID (e.g., 'ubuntu-22.04') and checks it against the Docker exclusion list. Only reached when running in CI (getIsCI() == true) on a non-Windows Linux host. The IOException is wrapped in a GradleException with a static message.

Source

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

        // Even if for some reason Docker exists on Windows agents, flag it as unsupported
        if (OS.current() == OS.WINDOWS) {
            return true;
        }

        // Only some hosts in CI are configured with Docker. We attempt to work out the OS
        // and version, so that we know whether to expect to find Docker. We don't attempt
        // to probe for whether Docker is available, because that doesn't tell us whether
        // Docker is unavailable when it should be.
        final Path osRelease = Paths.get("/etc/os-release");

        if (Files.exists(osRelease)) {
            Map<String, String> values;

            try {
                final List<String> osReleaseLines = Files.readAllLines(osRelease);
                values = parseOsRelease(osReleaseLines);
            } catch (IOException e) {
                throw new GradleException("Failed to read /etc/os-release", e);
            }

            final String id = deriveId(values);
            final boolean excluded = getLinuxExclusionList().contains(id);

            if (excluded) {
                LOGGER.warn("Linux OS id [{}] is present in the Docker exclude list. Tasks requiring Docker will be disabled.", id);
            }

            return excluded;
        }

        return false;
    }

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

View on GitHub (pinned to db6a809a66)

Solutions

  1. Verify /etc/os-release is a real, readable file: cat /etc/os-release inside the CI container.
  2. If using a minimal container, ensure os-release is installed (e.g., apt-get install -y base-files on Debian/Ubuntu).
  3. If the file is intentionally absent, ensure Files.exists returns false for it so the code path returns false (not excluded) instead of failing on read.
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight check before Docker-dependent tasks
Path osRelease = Paths.get("/etc/os-release");
if (Files.exists(osRelease) && !Files.isReadable(osRelease)) {
    throw new GradleException("/etc/os-release exists but is not readable");
}

Prevention

When it happens

Trigger: The build runs in CI (buildParams.getCi() is true), the OS is Linux (not Windows), /etc/os-release exists (Files.exists returns true), but Files.readAllLines throws IOException. This can happen if the file is a broken symlink, has restrictive permissions, or is on a filesystem that becomes unreadable mid-read.

Common situations: A CI container image lacks a properly mounted /etc/os-release or has it as an unreadable bind-mount. A minimal container (distroless, scratch-based) has a broken symlink at /etc/os-release pointing to /usr/lib/os-release which is missing. Filesystem corruption or a container runtime race condition during build startup.

Related errors


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