elastic/elasticsearch · error · UncheckedIOException

Could not write config file: {}

Error message

Could not write config file: {}

What it means

Thrown in createConfiguration() as the catch-all for any IOException during writing of the elasticsearch.yml config file AND copying additional config files from the distro's config/ dir. The try block covers Files.writeString(configFile, ...), Files.list(getDistroDir().resolve("config")), and Files.copy for each extra config file.

Source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:1483

                    .map(entry -> entry.getKey() + ": " + entry.getValue())
                    .collect(Collectors.joining("\n")),
                StandardOpenOption.TRUNCATE_EXISTING,
                StandardOpenOption.CREATE
            );

            final List<Path> configFiles;
            try (Stream<Path> stream = Files.list(getDistroDir().resolve("config"))) {
                configFiles = stream.collect(Collectors.toList());
            }
            logToProcessStdout("Copying additional config files from distro " + configFiles);
            for (Path file : configFiles) {
                Path dest = configFile.getParent().resolve(file.getFileName());
                if (Files.exists(dest) == false) {
                    Files.copy(file, dest);
                }
            }
        } catch (IOException e) {
            throw new UncheckedIOException("Could not write config file: " + configFile, e);
        }

        tweakJvmOptions(configFileRoot);
        LOGGER.info("Written config file:{} for {}", configFile, this);
    }

    private void tweakJvmOptions(Path configFileRoot) {
        LOGGER.info("Tweak jvm options {}.", configFileRoot.resolve("jvm.options"));
        Path jvmOptions = configFileRoot.resolve("jvm.options");
        try {
            String content = new String(Files.readAllBytes(jvmOptions));
            Map<ReplacementKey, String> expansions = jvmOptionExpansions();
            for (var entry : expansions.entrySet()) {
                ReplacementKey replacement = entry.getKey();
                String key = replacement.key();
                if (content.contains(key) == false) {
                    key = replacement.fallback();
                    if (content.contains(key) == false) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Free disk space and check write permissions on the testclusters working dir.
  2. Re-extract the distribution: delete build/testclusters/<id>/distro and the extracted-distribution cache, then re-run.
  3. Confirm getDistroDir()/config exists and is populated — if not, the distro build task failed silently upstream.
  4. On Windows, close any process holding the config file and add AV exclusions.
Defensive patterns

Strategy: try-catch

Validate before calling

if (Files.notExists(configFile.getParent())) {
    Files.createDirectories(configFile.getParent());
}
if (Files notExists(getDistroDir().resolve("config"))) {
    throw new IllegalStateException("distro config dir missing — re-extract");
}

Try / catch

try {
    Files.writeString(configFile, ...);
} catch (IOException e) {
    throw new UncheckedIOException("Could not write config file: " + configFile, e);
}

Prevention

When it happens

Trigger: Files.writeString fails (disk full, permissions, parent dir missing), or Files.list/Files.copy on the distro config dir fails (distro dir not extracted, config subdir missing, antivirus blocks the copy).

Common situations: Distro extraction was incomplete (no config/ subdir under the extracted distribution); the build/testclusters working dir is on a read-only or full volume; antivirus blocks writing the generated yml; a stale file handle on Windows prevents overwriting configFile.

Related errors


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