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
- Verify /etc/os-release is a real, readable file: cat /etc/os-release inside the CI container.
- If using a minimal container, ensure os-release is installed (e.g., apt-get install -y base-files on Debian/Ubuntu).
- 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
- Validate /etc/os-release readability in CI container setup scripts.
- Use Docker images that include a valid os-release file (e.g., official Ubuntu/Debian images).
- In CI, log the OS identification early to catch missing os-release before task execution.
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
- Failed to read {exclusionsFileAbsolutePath}
- Failed to write marker file
- Unable to create reaper JAR output directory {}
- Failed to write unicast_hosts for {}
- Failed to create working directory for {}, with: {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/b0f577281f460a42.
Report an issue: GitHub.