elastic/elasticsearch · error · UncheckedIOException
Can't copy extra jar dependency {} to {}
Error message
Can't copy extra jar dependency {} to {} What it means
Thrown by copyExtraJars() when Files.copy of a validated jar into <distro>/lib fails with an IOException, wrapped as UncheckedIOException. The jar passed the .jar suffix check but the copy itself failed. Message includes source filename and destination path for diagnosis.
Source
Thrown at build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java:653
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) {
throw new IllegalArgumentException("extra jar file " + from + " doesn't appear to be a JAR");
}
Path destination = getDistroDir().resolve("lib").resolve(from.getName());
try {
Files.copy(from.toPath(), destination, StandardCopyOption.REPLACE_EXISTING);
LOGGER.info("Added extra jar {} to {}", from.getName(), destination);
} catch (IOException e) {
throw new UncheckedIOException("Can't copy extra jar dependency " + from.getName() + " to " + destination, e);
}
});
}
private void configureSecurity() {
if (credentials.isEmpty() == false) {
logToProcessStdout("Setting up " + credentials.size() + " users");
credentials.forEach(
paramMap -> runElasticsearchBinScript(
getVersion().onOrAfter("6.3.0") ? "elasticsearch-users" : "x-pack/users",
paramMap.entrySet().stream().flatMap(entry -> Stream.of(entry.getKey(), entry.getValue())).toArray(String[]::new)
)
);
// If we added users, then also add the standard test roles
rolesFile(getBuildPluginFile("/roles.yml"));
}View on GitHub (pinned to db6a809a66)
Solutions
- Read the cause IOException for the exact FS error.
- rm -rf build/testclusters/<node> to force a clean distro dir on next start.
- Free disk / inodes; check permissions on build/testclusters.
- Shorten build path on Windows to avoid MAX_PATH in <distro>/lib/<long-jar-name>.
Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm distro lib dir is writable
Path lib = node.getDistroDir().resolve("lib");
if (Files.exists(lib) && !Files.isWritable(lib)) {
throw new IllegalStateException("<distro>/lib not writable: " + lib);
} Try / catch
try {
node.start();
} catch (UncheckedIOException e) {
if (e.getMessage().startsWith("Can't copy extra jar dependency")) {
throw new IllegalStateException("Jar copy FS failure: " + e.getCause(), e);
}
throw e;
} Prevention
- Keep build/testclusters owned by the Gradle user.
- Free disk before runs; monitor CI agent pressure.
- Shorten paths on Windows.
When it happens
Trigger: Disk full, permission denied on <distro>/lib, antivirus locking the destination on Windows, or path-too-long. The distro lib dir may not exist if setupNodeDistribution partially failed, or a prior copy left a read-only file at the destination despite REPLACE_EXISTING.
Common situations: Windows CI long path / AV lock. Permission residue from a root-owned prior run. Stale distro dir. Disk pressure on the build agent.
Related errors
- Failed to write unicast_hosts for {}
- Failed to create working directory for {}, with: {}
- Can't create extra config file for
- Can't append roles file {} to {}
- Unable to create reaper JAR output directory {}
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/109e97df59ba9d37.
Report an issue: GitHub.