gastownhall/beads · error
failed to rename temp file: %w
Error message
failed to rename temp file: %w
What it means
atomicWriteFile finishes by renaming the fully-written temp file over the destination; this wraps os.Rename failure. The temp file is removed, leaving any pre-existing destination intact.
Source
Thrown at cmd/bd/backup_export.go:120
tmpPath := tmp.Name()
if _, err := tmp.Write(data); err != nil {
_ = tmp.Close()
_ = os.Remove(tmpPath)
return fmt.Errorf("failed to write temp file: %w", err)
}
if err := tmp.Sync(); err != nil {
_ = tmp.Close()
_ = os.Remove(tmpPath)
return fmt.Errorf("failed to sync temp file: %w", err)
}
if err := tmp.Close(); err != nil {
_ = os.Remove(tmpPath)
return fmt.Errorf("failed to close temp file: %w", err)
}
if err := os.Rename(tmpPath, path); err != nil {
_ = os.Remove(tmpPath)
return fmt.Errorf("failed to rename temp file: %w", err)
}
return nil
}
// runBackupExport performs a Dolt-native backup to .beads/backup/.
// Returns the updated state.
func runBackupExport(ctx context.Context, force bool) (*backupState, error) {
dir, err := backupDir()
if err != nil {
return nil, err
}
state, err := loadBackupState(dir)
if err != nil {
return nil, err
}
// Change detection: skip if nothing changed (unless forced)View on GitHub (pinned to 71377f2769)
Solutions
- Check that .beads/backup_state.json is not a directory: if it is, remove it (rm -rf .beads/backup_state.json).
- Ensure .beads still exists and is writable at rename time; avoid concurrent processes deleting it.
- If .beads is a symlink, per the code's comment resolve it with filepath.EvalSymlinks semantics — keep .beads on the same filesystem as the workspace.
- Retry after resolving; the temp file was cleaned up automatically.
Example fix
// shell file .beads/backup_state.json # if 'directory': rm -rf .beads/backup_state.json && bd sync
Defensive patterns
Strategy: validation
Validate before calling
const p = ".beads/backup_state.json"
if st, err := os.Lstat(p); err == nil && st.IsDir() {
os.RemoveAll(p) // rename over a non-empty dir always fails
}
// ensure dest stays on the same filesystem as its temp file
if st, err := os.Stat(".beads"); err == nil && st.Mode()&os.ModeSymlink != 0 {
if resolved, err := filepath.EvalSymlinks(".beads"); err == nil {
_ = resolved // verify same-device with os.Stat + syscall same-device check
}
} Type guard
func renameTargetOk(path string) bool {
st, err := os.Lstat(path)
return err != nil || !st.IsDir()
} Try / catch
if err := saveBackupState(dir, state); err != nil {
if strings.Contains(err.Error(), "rename temp file") {
_ = os.RemoveAll(filepath.Join(dir, "backup_state.json"))
if retryErr := saveBackupState(dir, state); retryErr != nil {
return retryErr
}
} else if err != nil {
return err
}
} Prevention
- Don't mutate .beads concurrently with running bd commands
- Keep .beads a real directory, not a cross-filesystem symlink
- Remove any accidental directory at .beads/backup_state.json
When it happens
Trigger: os.Rename(tmpPath, path) fails: destination directory became unwritable/removed between create and rename, destination path changed type (e.g. backup_state.json is now a non-empty directory), or cross-filesystem rename (path relocated via symlink between mounts).
Common situations: Another process deleted/recreated .beads mid-run; .beads/backup_state.json exists as a directory; exotic filesystems lacking atomic rename; the symlink-target caveat noted in the file's comments (path resolving across filesystems via symlink).
Related errors
- failed to create temp file: %w
- failed to close temp file: %w
- retiring sidecar %s -> %s: %w
- ensureProxiedServerConfig: write %s: %w
- atomicfile: rename: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f81d47d5a4eaea17.
Report an issue: GitHub.