{"record":{"id":"351c92c5d7bfe614","repo":"docker/compose","slug":"closing-tar-w","errorCode":null,"errorMessage":"closing tar: %w","messagePattern":"closing tar: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sync/tar.go","lineNumber":332,"sourceCode":"\t})\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn result, nil\n}\n\nfunc tarArchive(ops []PathMapping) io.ReadCloser {\n\tpr, pw := io.Pipe()\n\tgo func() {\n\t\tab := NewArchiveBuilder(pw)\n\t\terr := ab.ArchivePathsIfExist(ops)\n\t\tif err != nil {\n\t\t\t_ = pw.CloseWithError(fmt.Errorf(\"adding files to tar: %w\", err))\n\t\t} else {\n\t\t\t// propagate errors from the TarWriter::Close() because it performs a final\n\t\t\t// Flush() and any errors mean the tar is invalid\n\t\t\tif err := ab.Close(); err != nil {\n\t\t\t\t_ = pw.CloseWithError(fmt.Errorf(\"closing tar: %w\", err))\n\t\t\t} else {\n\t\t\t\t_ = pw.Close()\n\t\t\t}\n\t\t}\n\t}()\n\treturn pr\n}\n\n// Dedupe the entries with last-entry-wins semantics.\nfunc dedupeEntries(entries []archiveEntry) []archiveEntry {\n\tseenIndex := make(map[string]int, len(entries))\n\tresult := make([]archiveEntry, 0, len(entries))\n\tfor i, entry := range entries {\n\t\tseenIndex[entry.header.Name] = i\n\t}\n\tfor i, entry := range entries {\n\t\tif seenIndex[entry.header.Name] == i {\n\t\t\tresult = append(result, entry)","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/internal/sync/tar.go#L314-L350","documentation":"After all entries are written, tarArchive calls ArchiveBuilder.Close, whose tar.Writer.Close performs a final flush of the archive (padding/blocks). If that fails, the pipe is closed with 'closing tar: %w' — the archive is invalid and extraction on the container side will fail with this message.","triggerScenarios":"ab.Close() erroring in the producer goroutine: underlying pipe already closed with an error by a failed consumer (container died mid-Untar), or a prior write left the writer in an error state so the final flush reports it.","commonSituations":"Container stopped/paused mid-extract, closing the pipe reader; the writer's final flush then fails and the error is attributed to 'closing tar' even though the root cause is on the container side.","solutions":["Check the wrapped cause: a closed-pipe error means the container-side reader aborted — diagnose that container (running? disk space? see error 102)","Ensure containers stay alive and unpaused for the full sync duration","Retry the sync once both sides are healthy; the archive cannot be salvaged mid-stream","If dockerd reports extract errors, free container disk space before retrying"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"null // final-flush failure is downstream of consumer health","typeGuard":null,"tryCatchPattern":"// 'closing tar' -> check the pipe consumer (container) aborted first; restart it, then re-run Sync to rebuild the archive cleanly","preventionTips":["Keep containers alive through the entire copy phase","Treat 'closing tar' with closed-pipe cause as a container-side signal, not a tar bug"],"tags":["tar","sync","io-pipe","go"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}