{"record":{"id":"b11a8ac3149d07f8","repo":"elastic/elasticsearch","slug":"failed-writing-tar-file-tarfile","errorCode":null,"errorMessage":"failed writing tar file [${tarFile}]","messagePattern":"failed writing tar file \\[(.+?)\\]","errorType":"exception","errorClass":"GradleException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/SymbolicLinkPreservingTar.java","lineNumber":81,"sourceCode":"            final Provider<RegularFile> tarFile,\n            final ArchiveOutputStreamFactory compressor,\n            final boolean isPreserveFileTimestamps\n        ) {\n            this.tarFile = tarFile;\n            this.compressor = compressor;\n            this.isPreserveFileTimestamps = isPreserveFileTimestamps;\n        }\n\n        @Override\n        public WorkResult execute(final CopyActionProcessingStream stream) {\n            try (\n                OutputStream out = compressor.createArchiveOutputStream(tarFile.get().getAsFile());\n                TarArchiveOutputStream tar = new TarArchiveOutputStream(out)\n            ) {\n                tar.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);\n                stream.process(new SymbolicLinkPreservingTarStreamAction(tar));\n            } catch (final IOException e) {\n                throw new GradleException(\"failed writing tar file [\" + tarFile + \"]\", e);\n            }\n\n            return WorkResults.didWork(true);\n        }\n\n        private class SymbolicLinkPreservingTarStreamAction implements CopyActionProcessingStreamAction {\n\n            private final TarArchiveOutputStream tar;\n\n            /*\n             * When Gradle walks the file tree, it will follow symbolic links. This means that if there is a symbolic link to a directory\n             * in the source file tree, we could otherwise end up duplicating the entries below that directory in the resulting tar archive.\n             * To avoid this, we track which symbolic links we have visited, and skip files that are children of symbolic links that we have\n             * already visited.\n             */\n            private final Set<File> visitedSymbolicLinks = new HashSet<>();\n\n            SymbolicLinkPreservingTarStreamAction(final TarArchiveOutputStream tar) {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/SymbolicLinkPreservingTar.java#L63-L99","documentation":"Thrown by SymbolicLinkPreservingTar's copy action when an IOException escapes the top-level try-with-resources that opens and writes the tar archive output stream. This wraps failures in creating/closing the compressed stream (gzip/bzip2/uncompressed) or any unhandled error during stream.process(...). It is the outer guard; per-entry failures are reported separately by error 178.","triggerScenarios":"The execute(CopyActionProcessingStream) method opens compressor.createArchiveOutputStream(tarFile) and a TarArchiveOutputStream over it; any IOException during opening, writing headers via stream.process, or closing the streams is caught by catch (final IOException e) and rethrown.","commonSituations":"The archiveFile output path is not writable or its parent directory does not exist; disk full while writing the tar; the output file is locked by another process (Windows); permissions denied on the target directory; the compression codec threw during stream construction.","solutions":["Check the archiveFile target path (shown as tarFile in the message): ensure its parent directory exists and is writable.","Free disk space on the target volume and retry.","On Windows, ensure no other process (antivirus, explorer, archiver) holds the output file.","Verify the task's compression setting matches a supported codec (GZIP/BZIP2/none).","If the failure originates from a single entry, look for error 178 which carries the per-entry 'could not add' detail."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import java.nio.file.*;\nimport java.io.File;\nFile target = archiveFile.getAsFile().get();\nFile parent = target.getParentFile();\nif (parent == null || !parent.exists())\n    throw new IllegalArgumentException(\"tar output parent missing: \" + parent);\nif (!parent.canWrite())\n    throw new IllegalArgumentException(\"tar output dir not writable: \" + parent);\nif (target.exists() && !target.isFile())\n    throw new IllegalArgumentException(\"tar target is not a regular file: \" + target);\nif (target.exists() && !target.canWrite())\n    throw new IllegalArgumentException(\"existing tar target not writable: \" + target);","typeGuard":null,"tryCatchPattern":"try (OutputStream out = compressor.createArchiveOutputStream(tarFile.get().getAsFile());\n     TarArchiveOutputStream tar = new TarArchiveOutputStream(out)) {\n    tar.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU);\n    stream.process(new SymbolicLinkPreservingTarStreamAction(tar));\n} catch (final IOException e) {\n    throw new GradleException(\"failed writing tar file [\" + tarFile + \"]\", e);\n}","preventionTips":["Ensure the archive output directory exists and is writable before running the task.","Free disk space on the target volume; tars can be large.","On Windows, ensure no process holds the output file."],"tags":["gradle","tar","archive","io","packaging"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}