netbirdio/netbird · error
write output: %w
Error message
write output: %w
What it means
Raised while streaming captured packets: writing a packet's bytes to the chosen output writer failed. The writer is either os.Stdout (default, or when piping to tshark/tcpdump with --pcap) or the temp file created for --output. The error wraps the underlying write error, so the cause is almost always a closed consumer (EPIPE) or a disk/filesystem problem (ENOSPC, EDQUOT).
Source
Thrown at client/cmd/capture.go:152
return req, nil
}
func streamCapture(ctx context.Context, cmd *cobra.Command, stream proto.DaemonService_StartCaptureClient, out io.Writer) error {
for {
pkt, err := stream.Recv()
if err != nil {
if ctx.Err() != nil {
cmd.PrintErrf("\nCapture stopped.\n")
return nil //nolint:nilerr // user interrupted
}
if err == io.EOF {
cmd.PrintErrf("\nCapture finished.\n")
return nil
}
return handleCaptureError(err)
}
if _, err := out.Write(pkt.GetData()); err != nil {
return fmt.Errorf("write output: %w", err)
}
}
}
// 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 {View on GitHub (pinned to 93e97f4bf1)
Solutions
- If piping, keep the consumer alive for the whole capture or drop the pipe and use --output file.pcap
- Check disk space on the output path: df -h <dir> and free space / raise quota
- If the consumer exiting early is intended, treat the capture as done — run with a bounded --duration instead of relying on the consumer to stop it
- Re-run writing to a location with capacity, optionally with --snap-len to cut bytes per packet
Example fix
# before: consumer exits early -> broken pipe netbird debug capture --pcap | head -c 1000000 > sample.pcap # after: bound the capture itself, write to a file netbird debug capture --pcap -d 10s -o sample.pcap
Defensive patterns
Strategy: validation
Validate before calling
// If writing to a file, check capacity first:
var st syscall.Statfs_t
if err := syscall.Statfs(filepath.Dir(outPath), &st); err == nil && st.Bavail*uint64(st.Bsize) < minFree {
return fmt.Errorf("insufficient space in %s", filepath.Dir(outPath))
} Try / catch
// In Go, treat EPIPE on stdout as a normal early stop:
if _, err := out.Write(pkt.GetData()); err != nil {
if errors.Is(err, syscall.EPIPE) {
return nil // consumer went away; capture is done
}
return fmt.Errorf("write output: %w", err)
} Prevention
- Use --output instead of pipes when the consumer may exit early
- Bound captures with --duration so unbounded streams cannot fill a disk
- Set --snap-len to cap per-packet bytes when only headers are needed
When it happens
Trigger: Piping the pcap stream into a consumer that exits early: netbird debug capture --pcap | head -c 1M, or tshark/tcpdump terminating on their own error, closing the pipe; redirecting to a file on a full disk (text or pcap mode); the temp output file's filesystem filling mid-capture.
Common situations: Using head or a viewer that stops reading; consumer crashes and the next Write gets EPIPE (Go then raises SIGPIPE handling nuances but the write error surfaces here); long captures on a small tmpfs; quota exceeded on the output directory.
Related errors
- invalid filter: %w
- duration must not be negative
- create output file: %w
- close output file: %w
- remove empty output file: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/b29559c1fbed287a.
Report an issue: GitHub.