gitbutlerapp/gitbutler · error
Failed to create symlink: {e}. No backup available to restor
Error message
Failed to create symlink: {e}. No backup available to restore. What it means
First macOS install: creating the 'but' symlink failed and no backup exists to restore. The new app may be installed, but the CLI link is missing. Same failure class as the restored variant - the link path is unwritable or occupied - except there is nothing to fall back to.
Source
Thrown at crates/but-installer/src/install_macos.rs:254
"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");
bail!("Installation failed but your previous installation was restored");
} else {View on GitHub (pinned to caf1f223d3)
Solutions
- mkdir -p ~/.local/bin and ensure it is user-writable, then re-run the installer
- Or create the link manually: ln -s /Applications/GitButler.app/Contents/MacOS/gitbutler-tauri ~/.local/bin/but
- Remove any directory occupying the but path first
- Verify ~/.local/bin is on PATH afterwards
Example fix
# manual completion of a first install that failed here mkdir -p ~/.local/bin ln -s /Applications/GitButler.app/Contents/MacOS/gitbutler-tauri ~/.local/bin/but
Defensive patterns
Strategy: validation
Validate before calling
// Pre-create and probe the symlink dir before a first install
let bin_dir = home.join(".local/bin");
std::fs::create_dir_all(&bin_dir)?; // fails clearly if HOME is not writable
let probe = bin_dir.join(".write-probe");
std::fs::write(&probe, b"")?;
std::fs::remove_file(&probe)?;
anyhow::ensure!(!bin_dir.join("but").is_dir(), "a directory occupies the 'but' path"); Try / catch
if let Err(e) = but_installer::run_installation_with_version(request, false) {
let msg = e.to_string();
if msg.contains("Failed to create symlink") && msg.contains("No backup available") {
// complete the first install by hand
let _ = std::fs::remove_file(home.join(".local/bin/but"));
std::os::unix::fs::symlink(
install_app.join("Contents/MacOS/gitbutler-tauri"),
home.join(".local/bin/but"))?;
}
return Err(e);
} Prevention
- Ensure ~/.local/bin exists and is writable before first install
- Remove any object occupying the 'but' link path
- Confirm ~/.local/bin is on PATH after install
When it happens
Trigger: unix_fs::symlink fails because ~/.local/bin cannot be created or written (parent not writable, read-only home), a non-file object already occupies the but path, or the link target directory is missing.
Common situations: Fresh machines with corporate read-only or root-owned home mounts; stray 'but' directory; PATH bin dir never created.
Related errors
- Failed to move new installation into place: {e}
- Failed to create symlink and failed to remove new installati
- Failed to create symlink: {e}. Previous installation was res
- Installation failed and no backup available to restore
- Installation failed and no backup available to restore
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/ceee142d9a7ee34b.
Report an issue: GitHub.