netbirdio/netbird · error

close archive writer: %w

Error message

close archive writer: %w

What it means

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.

Source

Thrown at client/internal/debug/debug.go:407

		if closeErr := bundlePath.Close(); closeErr != nil && err == nil {
			err = fmt.Errorf("close zip file: %w", closeErr)
		}

		if err != nil {
			if removeErr := os.Remove(bundlePath.Name()); removeErr != nil {
				log.Errorf("Failed to remove zip file: %v", removeErr)
			}
		}
	}()

	g.archive = zip.NewWriter(bundlePath)

	if err := g.createArchive(); err != nil {
		return "", err
	}

	if err := g.archive.Close(); err != nil {
		return "", fmt.Errorf("close archive writer: %w", err)
	}

	return bundlePath.Name(), nil
}

func (g *BundleGenerator) createArchive() error {
	if err := g.addReadme(); err != nil {
		return fmt.Errorf("add readme: %w", err)
	}

	if err := g.addStatus(); err != nil {
		return fmt.Errorf("add status: %w", err)
	}

	if err := g.addConfig(); err != nil {
		log.Errorf("failed to add config to debug bundle: %v", err)
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Free space on the volume backing the temp directory (check df on TMPDIR or deps.TempDir) and retry the bundle generation.
  2. Set deps.TempDir to a directory on a volume with enough free space before constructing the BundleGenerator.
  3. Check dmesg/journal for ENOSPC or EROFS errors on the temp filesystem and remount or expand it.
  4. If it reproduces consistently, capture the daemon log-level debug output to see whether an earlier addFileToZip write error was deferred to Close.

Example fix

// before
resp, err := generator.Generate() // fails: close archive writer: ... no space left on device

// after: point the bundle generator at a temp dir with free space
deps := debug.BundleDeps{
    TempDir: "/var/tmp/netbird-debug", // volume with sufficient space; ensure it exists
    // ...
}
generator := debug.NewBundleGenerator(cfg, deps)
resp, err := generator.Generate()
Defensive patterns

Strategy: retry

Validate before calling

// Go: check free space on the temp volume before generating
func tempDirHasSpace(dir string, need int64) bool {
    var st syscall.Statfs_t
    d := dir
    if d == "" {
        d = os.TempDir()
    }
    if err := syscall.Statfs(d, &st); err != nil {
        return false
    }
    return int64(st.Bavail)*int64(st.Bsize) > need
}

if !tempDirHasSpace(deps.TempDir, 64<<20) {
    return errors.New("insufficient temp space for debug bundle")
}

Try / catch

// Go idiom: inspect the wrapped error chain
if _, err := generator.Generate(); err != nil {
    if strings.Contains(err.Error(), "close archive writer") {
        // final-flush failure: free temp space and retry once
        cleanupTemp()
        if _, err2 := generator.Generate(); err2 == nil {
            return nil
        }
    }
    return fmt.Errorf("debug bundle: %w", err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/8584bacf52e70ea0. Report an issue: GitHub.