{"record":{"id":"8584bacf52e70ea0","repo":"netbirdio/netbird","slug":"close-archive-writer-w","errorCode":null,"errorMessage":"close archive writer: %w","messagePattern":"close archive writer: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/internal/debug/debug.go","lineNumber":407,"sourceCode":"\t\tif closeErr := bundlePath.Close(); closeErr != nil && err == nil {\n\t\t\terr = fmt.Errorf(\"close zip file: %w\", closeErr)\n\t\t}\n\n\t\tif err != nil {\n\t\t\tif removeErr := os.Remove(bundlePath.Name()); removeErr != nil {\n\t\t\t\tlog.Errorf(\"Failed to remove zip file: %v\", removeErr)\n\t\t\t}\n\t\t}\n\t}()\n\n\tg.archive = zip.NewWriter(bundlePath)\n\n\tif err := g.createArchive(); err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif err := g.archive.Close(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"close archive writer: %w\", err)\n\t}\n\n\treturn bundlePath.Name(), nil\n}\n\nfunc (g *BundleGenerator) createArchive() error {\n\tif err := g.addReadme(); err != nil {\n\t\treturn fmt.Errorf(\"add readme: %w\", err)\n\t}\n\n\tif err := g.addStatus(); err != nil {\n\t\treturn fmt.Errorf(\"add status: %w\", err)\n\t}\n\n\tif err := g.addConfig(); err != nil {\n\t\tlog.Errorf(\"failed to add config to debug bundle: %v\", err)\n\t}\n","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/internal/debug/debug.go#L389-L425","documentation":"Returned by BundleGenerator.Generate when g.archive.Close() fails while finalizing the debug bundle zip in client/internal/debug/debug.go:407. zip.Writer.Close flushes any buffered compressed data and writes the zip central directory to the temp file created by os.CreateTemp; it reports underlying I/O errors from that final write. When it fires, Generate's deferred cleanup closes and removes the partial zip file, so no bundle is produced.","triggerScenarios":"Running 'netbird debug bundle' (daemon RPC GenerateDebugBundle) when the filesystem holding the temp dir is out of space, read-only, or the temp file was closed/removed underneath the writer. A deferred write error from an earlier entry that only surfaces at Close also lands here.","commonSituations":"Full disk or small tmpfs (/tmp) on the peer machine; TMPDIR pointing at a volume with no free space; long-lived daemon whose tempDir (deps.TempDir) no longer exists; very large bundles (logs, capture files) exceeding remaining space during the final flush.","solutions":["Free space on the volume backing the temp directory (check df on TMPDIR or deps.TempDir) and retry the bundle generation.","Set deps.TempDir to a directory on a volume with enough free space before constructing the BundleGenerator.","Check dmesg/journal for ENOSPC or EROFS errors on the temp filesystem and remount or expand it.","If it reproduces consistently, capture the daemon log-level debug output to see whether an earlier addFileToZip write error was deferred to Close."],"exampleFix":"// before\nresp, err := generator.Generate() // fails: close archive writer: ... no space left on device\n\n// after: point the bundle generator at a temp dir with free space\ndeps := debug.BundleDeps{\n    TempDir: \"/var/tmp/netbird-debug\", // volume with sufficient space; ensure it exists\n    // ...\n}\ngenerator := debug.NewBundleGenerator(cfg, deps)\nresp, err := generator.Generate()","handlingStrategy":"retry","validationCode":"// Go: check free space on the temp volume before generating\nfunc tempDirHasSpace(dir string, need int64) bool {\n    var st syscall.Statfs_t\n    d := dir\n    if d == \"\" {\n        d = os.TempDir()\n    }\n    if err := syscall.Statfs(d, &st); err != nil {\n        return false\n    }\n    return int64(st.Bavail)*int64(st.Bsize) > need\n}\n\nif !tempDirHasSpace(deps.TempDir, 64<<20) {\n    return errors.New(\"insufficient temp space for debug bundle\")\n}","typeGuard":null,"tryCatchPattern":"// Go idiom: inspect the wrapped error chain\nif _, err := generator.Generate(); err != nil {\n    if strings.Contains(err.Error(), \"close archive writer\") {\n        // final-flush failure: free temp space and retry once\n        cleanupTemp()\n        if _, err2 := generator.Generate(); err2 == nil {\n            return nil\n        }\n    }\n    return fmt.Errorf(\"debug bundle: %w\", err)\n}","preventionTips":["Point BundleDeps.TempDir at a volume sized for logs + capture files, not a small tmpfs.","Free disk space or rotate logs before requesting bundles that include large captures.","Restart the daemon after changing temp-dir layout so no stale handles remain."],"tags":["go","netbird","zip","debug-bundle","disk-full","io"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}