elastic/elasticsearch · error · UncheckedIOException
Can't create extra config file for
Error message
Can't create extra config file for
What it means
Thrown by copyExtraConfigFiles() when Files.createDirectories / Files.copy raises an IOException while materialising an extra config file (source existed, but the copy itself failed). The IOException is wrapped in an UncheckedIOException with the generic message 'Can't create extra config file for' (note: the message is a prefix; the cause carries the detail).
Source
Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:626
private boolean isSettingTrue(String name) {
return Boolean.parseBoolean(settings.getOrDefault(name, "false").toString());
}
private void copyExtraConfigFiles() {
if (extraConfigFiles.isEmpty() == false) {
logToProcessStdout("Setting up " + extraConfigFiles.size() + " additional config files");
}
extraConfigFiles.forEach((destination, from) -> {
if (Files.exists(from.toPath()) == false) {
throw new TestClustersException("Can't create extra config file from " + from + " for " + this + " as it does not exist");
}
Path dst = configFile.getParent().resolve(destination);
try {
Files.createDirectories(dst.getParent());
Files.copy(from.toPath(), dst, StandardCopyOption.REPLACE_EXISTING);
LOGGER.info("Added extra config file {} for {}", destination, this);
} catch (IOException e) {
throw new UncheckedIOException("Can't create extra config file for", e);
}
});
}
/**
* Copies extra jars to the `/lib` directory.
* //TODO: Remove this when system modules are available
*/
private void copyExtraJars() {
List<File> extraJarFiles = this.extraJarConfigurations.stream()
.flatMap(fileCollection -> fileCollection.getFiles().stream())
.toList();
if (extraJarFiles.isEmpty() == false) {
logToProcessStdout("Setting up " + this.extraJarConfigurations.size() + " additional jar dependencies");
}
extraJarFiles.forEach(from -> {
if (from.getName().endsWith(".jar") == false) {View on GitHub (pinned to db6a809a66)
Solutions
- Inspect the wrapped IOException (cause) for the precise FS error and address it (permissions, disk, path length).
- On Windows, shorten the build path / enable long-path support.
- Clear build/testclusters and rerun so setupNodeDistribution recreates a clean distro dir.
- Confirm the destination string does not collide with an existing directory under config/.
Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm destination parent is writable and not a colliding file
Path configParent = node.getConfigFile().getParent();
if (!Files.isWritable(configParent)) {
throw new IllegalStateException("Config dir not writable: " + configParent);
} Try / catch
try {
node.start();
} catch (UncheckedIOException e) {
if (e.getMessage().contains("extra config file")) {
// surface FS cause: perms / disk / AV
throw new IllegalStateException("Config copy failed at FS level: " + e.getCause(), e);
}
throw e;
} Prevention
- Keep build/testclusters owned by the Gradle user.
- Shorten build paths on Windows.
- Disable or tune AV exclusions for the build dir on Windows CI.
When it happens
Trigger: Source file passes the existence check but the destination parent cannot be created or the bytes cannot be written: permissions on the distro config dir, read-only filesystem, antivirus interference, path-too-long, or a name collision with an existing directory.
Common situations: Windows MAX_PATH exceeded in deep testclusters paths. Antivirus locking destination on Windows CI. Permission residue from a prior root-owned run. Disk full mid-copy. Destination path collides with a directory created by setupNodeDistribution.
Related errors
- Failed to write unicast_hosts for {}
- Failed to create working directory for {}, with: {}
- Can't create extra config file from {} for {} as it does not
- Can't copy extra jar dependency {} to {}
- Can't append roles file {} to {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/e14b82eadce44201.
Report an issue: GitHub.