gitbutlerapp/gitbutler · warning
Moving it to {} to preserve your existing file
Error message
Moving it to {} to preserve your existing file What it means
Warning from the GitButler macOS installer's CLI setup step (install_macos.rs). When ~/.local/bin/but exists as a regular file rather than a symlink, the installer renames it to ~/.local/bin/but.backup.<unix-seconds> before creating its own symlink, so your existing binary is never destroyed. The subsequent fs::rename uses '?', so if the rename itself fails the install aborts with an io::Error. After the swap, 'but' points to ~/Applications/GitButler.app/Contents/MacOS/gitbutler-tauri and your old binary lives at the printed backup path.
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 caf1f223d3)
Solutions
- Let the installer finish - your file is preserved at the printed but.backup.<timestamp> path; verify with ls -la ~/.local/bin/but*
- If you still need the old binary on PATH, rename the backup: mv ~/.local/bin/but.backup.<timestamp> ~/.local/bin/but-custom
- Preempt on future installs: mv ~/.local/bin/but ~/bin/but-custom before running the installer
- If the install aborted on the rename, fix ownership/permissions of ~/.local/bin (ls -ld ~/.local/bin; chown -R $(whoami) ~/.local/bin) and re-run
Example fix
# before ls -la ~/.local/bin/but -rwxr-xr-x 1 me staff 24563200 but # real binary, will be moved # after installer runs (auto-backup) but -> ~/Applications/GitButler.app/Contents/MacOS/gitbutler-tauri but.backup.1755689000 # your original, kept # keep it on PATH under a new name if needed: mv ~/.local/bin/but.backup.1755689000 ~/.local/bin/but-custom
Defensive patterns
Strategy: validation
Validate before calling
# Before running the GitButler macOS installer: if [ -f ~/.local/bin/but ] && [ ! -L ~/.local/bin/but ]; then echo "regular file at ~/.local/bin/but - will be moved to but.backup.<ts>" mv ~/.local/bin/but ~/bin/but-custom # or wherever you want it fi
Prevention
- Check 'ls -la ~/.local/bin/but' before installs and decide the file's fate yourself instead of relying on the auto-backup
- Keep custom binaries out of ~/.local/bin or under distinct names (but-custom) so the installer-managed 'but' slot stays free
- If you rely on the auto-backup, record the but.backup.<timestamp> path from the log immediately - nothing else tracks it
When it happens
Trigger: Running the macOS app installer while ~/.local/bin/but is a real file: a cargo-installed but CLI, a homebrew-placed binary, a manually compiled/copied executable, or a dotfile manager that writes actual binaries into ~/.local/bin. The branch is taken when but_symlink.exists() && !but_symlink.is_symlink() (install_macos.rs:118).
Common situations: Developer previously built/installed the but CLI from source; another tool also named 'but' on PATH; leftover binary from an earlier manual install; ~/.local/bin shared across machines via sync.
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 {} (not a symlink)
- Found existing 'but' symlink pointing to: {existing_target_s
- This will be replaced with GitButler's 'but' command
- Failed to create symlink: {e} - attempting to restore backup
- Failed to move new installation into place - restoring backu
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/27a32c2ef655a9ad.
Report an issue: GitHub.