netbirdio/netbird · error
rename output file: %w
Error message
rename output file: %w
What it means
The final atomic-publish step of pcap output: os.Rename of the temp file onto the requested --output path failed. The temp file lives in the same directory by design, so cross-device rename (EXDEV) should not occur — the realistic causes are a missing target directory, a target that is an existing directory, or permission issues on the directory/name. The capture data itself is lost from the final path when this fires (the temp file may remain).
Source
Thrown at client/cmd/capture.go:183
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
- Confirm the parent directory of -o still exists when the capture ends; for long captures prefer a stable directory (e.g. /var/tmp or $HOME) that tmp cleaners do not purge
- Never pass a directory as -o; the value must be a file path
- If a stray .tmp file remains next to the target, rename it manually: mv /path/x.pcap.*.tmp /path/x.pcap to salvage the data
- Re-run with a shorter --duration to verify the path works, then scale up
Example fix
# before: long capture into a cleaned tmp dir netbird debug capture -d 24h -o /tmp/long.pcap # after: durable location netbird debug capture -d 24h -o /var/tmp/netbird/long.pcap # mkdir -p /var/tmp/netbird first
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the parent exists and is a real directory, and the target name is not a dir:
dir := filepath.Dir(outPath)
if err := os.MkdirAll(dir, 0o755); err != nil { return err }
if fi, err := os.Stat(outPath); err == nil && fi.IsDir() {
return fmt.Errorf("%s is a directory", outPath)
} Try / catch
// After a rename failure, salvage data from the temp file:
if err := os.Rename(tmpPath, outPath); err != nil {
if data, rerr := os.ReadFile(tmpPath); rerr == nil {
os.WriteFile(outPath+".recovered", data, 0o644)
}
return err
} Prevention
- Never point -o at a mountpoint root or an existing directory
- For long captures use a directory no tmp-cleaner purges (/var/tmp over /tmp)
- Pass an absolute path so a changed cwd cannot redirect the rename target
When it happens
Trigger: The output directory was removed between capture start and finish (tmp cleaner, scripted cleanup of /tmp); --output names an existing directory (netbird debug capture -o /tmp — basename '/tmp.*.tmp' created in / renames onto /tmp); directory not writable for rename (w+x needed) though CreateTemp succeeded via a race; target file exists and is owned by another user on systems where rename over it is denied.
Common situations: Long captures into systemd-tmpfiles-cleaned /tmp: cleaner wipes the dir mid-run; output path supplied by a script that also mkdirs/rms concurrently; -o pointing at a mountpoint root.
Related errors
- create output file: %w
- close output file: %w
- remove empty output file: %w
- invalid filter: %w
- duration must not be negative
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/3f89730322fb4226.
Report an issue: GitHub.