netbirdio/netbird · error

close output file: %w

Error message

close output file: %w

What it means

During output finalization the cleanup function closes the temp pcap file and accumulates a close error here. The data was already streamed; this indicates the close syscall itself failed, which is rare for local files and usually points to deferred write errors being reported at close time (NFS/network filesystems) or the descriptor being invalidated externally. It is collected into a multierror together with any later rename result.

Source

Thrown at client/cmd/capture.go:173

}

// captureOutput returns the writer for capture data and a cleanup function
// that finalizes the file. Errors from the cleanup must be propagated.
func captureOutput(cmd *cobra.Command) (io.Writer, func() error, error) {
	outPath, _ := cmd.Flags().GetString("output")
	if outPath == "" {
		return os.Stdout, func() error { return nil }, nil
	}

	f, err := os.CreateTemp(filepath.Dir(outPath), filepath.Base(outPath)+".*.tmp")
	if err != nil {
		return nil, nil, fmt.Errorf("create output file: %w", err)
	}
	tmpPath := f.Name()
	return f, func() error {
		var merr *multierror.Error
		if err := f.Close(); err != nil {
			merr = multierror.Append(merr, fmt.Errorf("close output file: %w", err))
		}
		fi, statErr := os.Stat(tmpPath)
		if statErr != nil || fi.Size() == 0 {
			if rmErr := os.Remove(tmpPath); rmErr != nil && !os.IsNotExist(rmErr) {
				merr = multierror.Append(merr, fmt.Errorf("remove empty output file: %w", rmErr))
			}
			return nberrors.FormatErrorOrNil(merr)
		}
		if err := os.Rename(tmpPath, outPath); err != nil {
			merr = multierror.Append(merr, fmt.Errorf("rename output file: %w", err))
			return nberrors.FormatErrorOrNil(merr)
		}
		cmd.PrintErrf("Wrote %s\n", outPath)
		return nberrors.FormatErrorOrNil(merr)
	}, nil
}

func handleCaptureError(err error) error {

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Retry the capture writing to a local filesystem (e.g. /tmp) and copy the file afterwards
  2. If on NFS, check mount health (dmesg, mount stats) and remount or move to local storage
  3. Check free space — a full disk can surface as an error at close rather than at write
  4. Update/report if it reproduces on a plain local ext4/xfs path, since that would be a genuine bug in the capture path

Example fix

# before: pcap written directly to a network mount
netbird debug capture -d 30s -o /mnt/nfs/capture.pcap

# after: capture locally, then copy
cd /tmp && netbird debug capture -d 30s -o capture.pcap && cp capture.pcap /mnt/nfs/
Defensive patterns

Strategy: fallback

Validate before calling

// Prefer a local filesystem target for pcaps:
if isNetworkMount(dir) { // e.g. /proc/mounts type nfs|cifs|fuse
    dir = os.TempDir()
}

Try / catch

// Capture locally, copy after success:
if err := cleanup(); err != nil {
    if isCloseOnly(err) { // data already flushed; copy from tmp if present
        tryCopyTmpToFinal()
    }
}

Prevention

When it happens

Trigger: --output on NFS or a network mount where flushed data fails at close; the process's file descriptor closed underneath it by an external tool or a filesystem forced unmount; SELinux/AppArmor interfering with the file after creation.

Common situations: Writing pcaps to a network share (home NFS, k8s hostPath with quirks); very long captures where the mount drops; exotic filesystems (FUSE) that return errors on close after background write failures.

Related errors


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