netbirdio/netbird · warning

remove empty output file: %w

Error message

remove empty output file: %w

What it means

In output finalization, when the temp file is empty (zero packets captured) or its Stat failed, the cleanup removes the temp file so no stray .tmp file is left behind. This error means os.Remove failed with something other than 'file does not exist' — e.g. permission loss on the directory between creation and removal, or the file being held immutable. It is accumulated into the returned multierror.

Source

Thrown at client/cmd/capture.go:178

	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 {
	if s, ok := status.FromError(err); ok {
		return fmt.Errorf("%s", s.Message())
	}
	return err
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check directory permissions and MAC denials (ausearch -m AVC for SELinux) for the output directory
  2. Ensure no antivirus/EDR is removing or locking the .tmp files; exclude the capture directory if policy allows
  3. Retry with an output directory you fully control (e.g. under /tmp)
  4. If Stat failed rather than Remove, the temp file may already be gone — verify no stray *.tmp remains and treat the message as diagnostic

Example fix

# before: writing where a policy tool intervenes
netbird debug capture -o /opt/protected/x.pcap

# after: use a controlled writable directory
netbird capture -o /tmp/x.pcap 2>/dev/null || netbird debug capture -o "$HOME/x.pcap"
Defensive patterns

Strategy: fallback

Validate before calling

// Reduce exposure: use a dedicated, policy-free output dir owned by the invoker:
// mkdir -p ~/netbird-captures && netbird debug capture -o ~/netbird-captures/x.pcap

Try / catch

// Best-effort cleanup: ignore remove failures for empty temp files, they are cosmetic:
if rmErr := os.Remove(tmpPath); rmErr != nil && !os.IsNotExist(rmErr) {
    log.Warnf("leftover temp file %s: %v", tmpPath, rmErr)
}

Prevention

When it happens

Trigger: Directory permissions changed or the process lost write permission on the output directory between CreateTemp and cleanup; another process/user deleted or locked the temp file on platforms that disallow removal; immutable attribute (chattr +i) set on the file.

Common situations: Security tooling quarantining pcap-like temp files mid-run; permission-revoking MAC policy (SELinux) reacting to the new file; extremely rare in normal single-user CLI use — usually seen together with unusual cleanup failures of the same run.

Related errors


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