gitbutlerapp/gitbutler · error
Failed to create symlink: {e}. Previous installation was res
Error message
Failed to create symlink: {e}. Previous installation was restored. What it means
Symlink creation for 'but' failed, but the backup app was restored and the previous symlink target recreated - the prior installation is functional again. The original symlink error is embedded. Note the code ignores the result of remove_file on the old link first, so a directory named 'but' on the link path surfaces here as an EEXIST/EISDIR symlink failure.
Source
Thrown at crates/but-installer/src/install_macos.rs:252
// Symlink creation failed - rollback to backup
warn(&format!(
"Failed to create symlink: {e} - attempting to restore backup"
));
if install_app_backup.exists() {
if let Err(remove_err) = fs::remove_dir_all(&install_app) {
bail!(
"Failed to create symlink and failed to remove new installation during rollback: {}. Backup at: {}",
remove_err,
install_app_backup.display()
);
}
fs::rename(&install_app_backup, &install_app)?;
let restored_target = install_app.join("Contents/MacOS/gitbutler-tauri");
let _ = fs::remove_file(&but_symlink);
let _ = unix_fs::symlink(&restored_target, &but_symlink);
bail!("Failed to create symlink: {e}. Previous installation was restored.");
} else {
bail!("Failed to create symlink: {e}. No backup available to restore.");
}
}
if !validate_installed_binary(&but_symlink) {
// Try to restore backup
warn("Final installation verification failed - attempting to restore backup");
if install_app_backup.exists() {
fs::remove_dir_all(&install_app)?;
fs::rename(&install_app_backup, &install_app)?;
let restored_target = install_app.join("Contents/MacOS/gitbutler-tauri");
let _ = fs::remove_file(&but_symlink);
unix_fs::symlink(&restored_target, &but_symlink)?;
if validate_installed_binary(&but_symlink) {
success("Backup was restored successfully");View on GitHub (pinned to caf1f223d3)
Solutions
- Inspect the embedded {e}: EEXIST/EISDIR - remove whatever occupies the link path (rm -rf ~/.local/bin/but if it is a stray directory)
- Fix ownership of the bin dir: chown -R $(whoami) ~/.local/bin
- Re-run the installer; the previous version keeps working meanwhile
Example fix
# before: a directory blocks the symlink path ls -ld ~/.local/bin/but # drwxr-xr-x ... rm -rf ~/.local/bin/but # after but-installer 0.18.7
Defensive patterns
Strategy: validation
Validate before calling
// The 'but' link path must be absent or a removable file, never a directory
let but_link = home.join(".local/bin/but");
if but_link.symlink_metadata().is_ok() {
anyhow::ensure!(!but_link.is_dir(),
"~/.local/bin/but is a directory; remove it before reinstalling");
} Try / catch
match but_installer::run_installation_with_version(request, false) {
Err(e) if e.to_string().contains("Failed to create symlink")
&& e.to_string().contains("was restored") =>
{
// old version intact; clear the link path and retry once
let _ = std::fs::remove_file(home.join(".local/bin/but"));
but_installer::run_installation_with_version(request, false)
}
result => result,
} Prevention
- Never create a directory named 'but' in the PATH bin dir
- Keep ~/.local/bin user-owned
- Remove stale 'but' links before scripted updates
When it happens
Trigger: A directory (not a file/symlink) occupies ~/.local/bin/but so the pre-remove fails silently and symlink(2) returns EEXIST; or the symlink directory is not writable by the current user. Backup exists, so restore succeeds.
Common situations: A stray 'but' directory from a botched manual install; root-owned ~/.local/bin after running something with sudo; restored cleanly afterwards.
Related errors
- Failed to install new version: {e}. Previous installation re
- Failed to create symlink and failed to remove new installati
- Failed to create symlink: {e}. No backup available to restor
- Installation failed but your previous installation was resto
- New installation verification failed - 'but' binary cannot r
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/bd6735b69f5eabac.
Report an issue: GitHub.