elastic/elasticsearch · error · GradleException

could not add [ ] to tar file [ ]

Error message

could not add [${details}] to tar file [${tarFile}]

What it means

Thrown by SymbolicLinkPreservingTarStreamAction.handleProcessingException when writing a single archive entry fails with IOException. It wraps the per-entry failure (file, directory, or symbolic-link) with both the offending FileCopyDetails and the target tar, making it possible to identify exactly which input could not be added.

Solutions

  1. Inspect the details object in the message to identify the exact source path, then check it exists and is readable.
  2. For a broken symbolic link, fix or remove the symlink in the source tree.
  3. Ensure the build user has read/traverse permissions on the offending path and its parents.
  4. Avoid mutating the task's input tree while the build runs; if generated, ensure the generating task is a proper dependency.
  5. If a file changes size mid-copy, snapshot/stage the inputs into a stable directory first.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate each input before the tar action processes it:
import java.nio.file.*;
void checkReadable(File f) {
    if (!Files.exists(f.toPath()))
        throw new IllegalArgumentException("missing input: " + f);
    if (!Files.isReadable(f.toPath()))
        throw new IllegalArgumentException("unreadable input: " + f);
}
// For symlinks also check the target:
if (Files.isSymbolicLink(f.toPath())) {
    Path target = Files.readSymbolicLink(f.toPath());
    // ensure target resolves / is accessible
}

Try / catch

try {
    tar.putArchiveEntry(entry);
    details.copyTo(tar);
    tar.closeArchiveEntry();
} catch (final IOException e) {
    handleProcessingException(details, e); // throws GradleException with details + tarFile
}

Prevention

When it happens

Trigger: In visitFile/visitDirectory/visitSymbolicLink: tar.putArchiveEntry(entry), details.copyTo(tar), Files.readSymbolicLink(...), or tar.closeArchiveEntry() throws IOException; handleProcessingException rethrows as GradleException with the details + tarFile. Common low-level causes: a path exceeding 100 chars without LONGFILE_GNU (mitigated here by setLongFileMode(LONGFILE_GNU)), a symlink target that cannot be read, or a file that vanished during the copy.

Common situations: A source file is deleted/moved between Gradle's tree walk and the tar write; a symbolic link target is unreadable or broken; a file grows during copy so entry.setSize mismatches the bytes written; very long relative paths; reading a symlink requires permissions the build user lacks.

Related errors


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

Appendix: source

Thrown at build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/SymbolicLinkPreservingTar.java:186

                }
            }

            private void visitFile(final FileCopyDetailsInternal details) {
                final TarArchiveEntry entry = new TarArchiveEntry(details.getRelativePath().getPathString());
                entry.setModTime(getModTime(details));
                entry.setMode(UnixStat.FILE_FLAG | details.getPermissions().toUnixNumeric());
                entry.setSize(details.getSize());
                try {
                    tar.putArchiveEntry(entry);
                    details.copyTo(tar);
                    tar.closeArchiveEntry();
                } catch (final IOException e) {
                    handleProcessingException(details, e);
                }
            }

            private void handleProcessingException(final FileCopyDetailsInternal details, final IOException e) {
                throw new GradleException("could not add [" + details + "] to tar file [" + tarFile + "]", e);
            }

        }

        private long getModTime(final FileCopyDetails details) {
            return isPreserveFileTimestamps ? details.getLastModified() : 0;
        }

    }

}

View on GitHub (pinned to db6a809a66)