elastic/elasticsearch · error · UncheckedIOException

Failed to copy {} to {}

Error message

Failed to copy {} to {}

What it means

Thrown by syncWithCopy — the copy-based fallback used when hard-linking is not desired. Files.copy(s, d) failed with IOException. This path is the more permissive sibling of syncWithLinks and is used when the sync method is selected as copy rather than link.

Source

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

     * @param destinationRoot destination to link to
     */
    private void syncWithLinks(Path sourceRoot, Path destinationRoot) {
        sync(sourceRoot, destinationRoot, (Path d, Path s) -> {
            try {
                Files.createLink(d, s);
            } catch (IOException e) {
                // Note does not work for network drives, e.g. Vagrant
                throw new LinkCreationException("Failed to create hard link " + d + " pointing to " + s, e);
            }
        });
    }

    private void syncWithCopy(Path sourceRoot, Path destinationRoot) {
        sync(sourceRoot, destinationRoot, (Path d, Path s) -> {
            try {
                Files.copy(s, d);
            } catch (IOException e) {
                throw new UncheckedIOException("Failed to copy " + s + " to " + d, e);
            }
        });
    }

    private void sync(Path sourceRoot, Path destinationRoot, BiConsumer<Path, Path> syncMethod) {
        assert Files.exists(destinationRoot) == false;
        try {
            Files.walkFileTree(sourceRoot, new SimpleFileVisitor<>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    Path relativeDestination = sourceRoot.relativize(dir);
                    if (relativeDestination.getNameCount() <= 1) {
                        return FileVisitResult.CONTINUE;
                    }
                    // Throw away the first name as the archives have everything in a single top level folder we are not interested in
                    relativeDestination = relativeDestination.subpath(1, relativeDestination.getNameCount());
                    Path destination = destinationRoot.resolve(relativeDestination);
                    Files.createDirectories(destination);

View on GitHub (pinned to db6a809a66)

Solutions

  1. Free space on the volume holding the testclusters working dir and check disk quota.
  2. Disable/reconfigure antivirus that may block writes into the gradle build directory.
  3. Ensure no other gradle daemon or test is concurrently mutating the same sourceRoot.
  4. Inspect the wrapped IOException for the specific OS error and address that.
Defensive patterns

Strategy: try-catch

Try / catch

try {
    Files.copy(s, d);
} catch (IOException e) {
    throw new UncheckedIOException("Failed to copy " + s + " to " + d, e);
}

Prevention

When it happens

Trigger: Files.copy throws when the destination's parent does not exist, the source vanished mid-walk, disk is full, or a permission/security manager denied the write. Happens inside the sync() walker for each file under sourceRoot.

Common situations: Disk full under the build dir; an antivirus/EDR blocked the write; the source tree changed during the walk (a concurrent process deleted a file between walkFileTree enumeration and the copy); running on a read-only or quota-limited filesystem.

Related errors


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