gastownhall/beads · error

atomicfile: rename: %w

Error message

atomicfile: rename: %w

What it means

The final step of an atomic write is os.Rename(tempFile, target). If the rename fails, the temp file is removed and this wrapped error is returned; the original target file (if any) is never partially modified.

Source

Thrown at internal/atomicfile/atomicfile.go:95

		_ = w.f.Close()
		_ = os.Remove(w.f.Name())
		return fmt.Errorf("atomicfile: chmod: %w", err)
	}

	if err := w.f.Sync(); err != nil {
		_ = w.f.Close()
		_ = os.Remove(w.f.Name())
		return fmt.Errorf("atomicfile: sync: %w", err)
	}

	if err := w.f.Close(); err != nil {
		_ = os.Remove(w.f.Name())
		return fmt.Errorf("atomicfile: close: %w", err)
	}

	if err := os.Rename(w.f.Name(), w.target); err != nil {
		_ = os.Remove(w.f.Name())
		return fmt.Errorf("atomicfile: rename: %w", err)
	}

	return nil
}

// Abort discards the temp file without renaming. The target is untouched.
// Safe to call multiple times or after Close.
func (w *Writer) Abort() error {
	if w.done {
		return nil
	}
	w.done = true
	_ = w.f.Close()
	return os.Remove(w.f.Name())
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Ensure no other process locks or removes the target during the write (close editors/sync tools, use file locking)
  2. Verify target directory exists and is writable at rename time
  3. Keep the target on the same filesystem as the temp file (rename is same-FS only)

Example fix

// before
atomicfile.Create("/mnt/usb/out.jsonl", 0644) // temp on /tmp FS? mismatch
// after
atomicfile.Create("/mnt/usb/.beads/out.jsonl", 0644) // temp created in same dir
Defensive patterns

Strategy: retry

Validate before calling

dir := filepath.Dir(path)
if info, err := os.Stat(dir); err != nil || !info.IsDir() {
    return fmt.Errorf("target dir missing: %s", dir)
}

Try / catch

err := writeAtomic(path, data) // wraps atomicfile
for i := 0; i < 3 && err != nil; i++ {
    if strings.Contains(err.Error(), "atomicfile: rename") {
        time.Sleep(100 * time.Millisecond) // transient lock on Windows/sync tools
        err = writeAtomic(path, data)
        continue
    }
    break
}

Prevention

When it happens

Trigger: Rename fails when the target directory became unwritable or was removed mid-write, when target and temp end up on different filesystems, when the target path is a directory, or on Windows when the target is open/locked by another process.

Common situations: Another process deleting .beads while bd writes, exporting onto a different mount than expected, or Windows antivirus/indexer holding the destination file open.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/d0f2c48d843359a7. Report an issue: GitHub.