gitbutlerapp/gitbutler · info
Moving it to to preserve your existing file
Error message
Moving it to {} to preserve your existing file What it means
Second warning in the same flow: the installer tells the user exactly where the displaced 'but' binary is being moved (but.backup.<unix-timestamp>) so their original file is preserved before the symlink replaces it. Immediately after, fs::rename performs the move.
Solutions
- Note the printed backup path; your original binary is intact there and can be restored with mv if needed.
- If the rename itself fails (logged error), move the file manually: mv <bin_dir>/but <bin_dir>/but.backup.manual and re-run the installer.
- Remove the stale binary if it is no longer wanted, then re-run the installer for a clean symlink.
- Check timestamps if multiple but.backup.* files accumulate and delete old ones you don't need.
Defensive patterns
Strategy: try-catch
Validate before calling
# Note and verify backup location after install
import glob, os
print(glob.glob(os.path.expanduser('<bin_dir>/but.backup.*'))) Try / catch
// Ensure the rename away of the old binary reports failures clearly
fs::rename(&but_symlink, &but_backup)
.map_err(|e| anyhow!("could not preserve existing but binary: {e}"))?; Prevention
- Record the printed backup path before confirming the install
- Clean up old but.backup.* files periodically, keeping the most recent one
- Restore with mv if the new symlinked version misbehaves
When it happens
Trigger: Raised in install_app (download_and_install_app) right after detecting the non-symlink 'but' binary, immediately before fs::rename(&but_symlink, &but_backup); always paired with the preceding 'already exists' warning.
Common situations: Same collision scenario as the preceding warning: upgrades from copy-based installs, local builds, or package-manager-owned binaries in the target bin dir.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- A 'but' binary already exists at
- Failed to create symlink
- Found existing 'but' symlink pointing to
- This will be replaced with GitButler's 'but' command
- Attempting to restore backup
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/27a32c2ef655a9ad.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-installer/src/install_macos.rs:130
fs::create_dir_all(&bin_dir)?;
// Check for existing 'but' and detect channel switching
let but_symlink = bin_dir.join("but");
let but_new = bin_dir.join("but.new");
if but_symlink.exists() && !but_symlink.is_symlink() {
// 'but' exists but is not a symlink
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap_or_default()
.as_secs();
let timestamp = format!("{now}");
let but_backup = bin_dir.join(format!("but.backup.{timestamp}"));
warn(&format!(
"A 'but' binary already exists at {} (not a symlink)",
but_symlink.display()
));
warn(&format!(
"Moving it to {} to preserve your existing file",
but_backup.display()
));
fs::rename(&but_symlink, &but_backup)?;
info(&format!(
"Your original 'but' has been saved to: {}",
but_backup.display()
));
} else if but_symlink.is_symlink() {
let existing_target = fs::read_link(&but_symlink)?;
let existing_target_str = existing_target.to_string_lossy();
// Detect channel switching
let previous_channel = if existing_target_str.contains("Nightly") {
Some(Channel::Nightly)
} else if existing_target_str.contains("/GitButler.app/") {
Some(Channel::Release)
} else {View on GitHub (pinned to 58e5313667)