{"record":{"id":"bb8c1892efac0241","repo":"docker/compose","slug":"adding-files-to-tar-w","errorCode":null,"errorMessage":"adding files to tar: %w","messagePattern":"adding files to tar: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/sync/tar.go","lineNumber":327,"sourceCode":"\t\t\tinfo:   info,\n\t\t\theader: header,\n\t\t})\n\n\t\treturn nil\n\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 {","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/docker/compose/blob/ddc4b044b62e9f715212ea4143fa830fac76382f/internal/sync/tar.go#L309-L345","documentation":"tarArchive runs ArchiveBuilder in a goroutine writing into an io.Pipe. If collecting/walking/writing entries fails (any of errors 103-111), the pipe is closed with 'adding files to tar: %w', which surfaces on the reading side — typically as the Untar/put-archive call failing with this message for every container being synced.","triggerScenarios":"ArchivePathsIfExist returning an error in the producer goroutine: unreadable paths (103/110), vanished or mid-write files (104-109), or relative-path computation failures (111). The message appears on the consumer side of the pipe, often for all 16 parallel container copies at once.","commonSituations":"compose watch failing on all replicas simultaneously with the same wrap — the tell that the local archive build, not the containers, is broken; usually triggered by source-tree churn or permissions.","solutions":["Unwrap the %w — the inner error is one of errors 103-111 and names the real host-side problem; fix that first","Check whether the named host tree was mid-rewrite (build running) and re-sync when idle","Fix local permissions on the sync root (see 103/110)","Do not restart containers in response to this error appearing everywhere at once — it is a local-side failure"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// validate the archive can be built before syncing to any container (dry-run into io.Discard)\nif err := NewArchiveBuilder(io.Discard).ArchivePathsIfExist(paths); err != nil { return err }","typeGuard":null,"tryCatchPattern":"// on 'adding files to tar', unwrap the inner error (one of errors 103-111), fix the named host path, then retry — do not touch the containers","preventionTips":["Dry-run archive builds in watch tooling before fan-out","Keep synced trees free of unreadable/volatile files"],"tags":["tar","sync","goroutine","io-pipe","go"],"backgroundTag":null,"analyzedSha":"ddc4b044b62e9f715212ea4143fa830fac76382f","analyzedAt":"2026-08-15T13:31:42.319Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}