gitbutlerapp/gitbutler · error
Failed to create symlink
Error message
Failed to create symlink: {e}. No backup available to restore. What it means
Creating the `but` symlink failed and there was no backup of a previous installation to restore (first install). The new app remains at the install path, but the `but` command symlink is not created, so the CLI is unusable until the user fixes the symlink problem and retries.
Solutions
- Check and clear the ~/.local/bin/but path (`ls -la ~/.local/bin/but`) then retry
- Ensure ~/.local/bin exists and is writable by the current user
- If the filesystem does not support symlinks, move the install to a local APFS volume
- Manually link as a workaround: `ln -s <install>/Contents/MacOS/gitbutler-tauri ~/.local/bin/but`
Example fix
// before
unix_fs::symlink(&final_target, &but_symlink)?;
// after: caller-side check before install
let link = home.join(".local/bin/but");
if let Ok(m) = fs::symlink_metadata(&link) {
if !m.file_type().is_symlink() {
bail!("{} exists and is not a symlink - move it first", link.display());
}
} Defensive patterns
Strategy: validation
Validate before calling
let bin = home.join(".local/bin");
let link = bin.join("but");
if !bin.exists() {
fs::create_dir_all(&bin)?;
}
if let Ok(m) = fs::symlink_metadata(&link) {
if !m.file_type().is_symlink() {
bail!("{} blocks the installer - remove it first", link.display());
}
}
// sanity: symlinks supported on this filesystem
let probe = bin.join(".symlink-probe");
std::os::unix::fs::symlink(&bin.join("."), &probe)?;
let _ = fs::remove_file(&probe); Type guard
fn symlink_supported(dir: &Path) -> bool {
let probe = dir.join(".symlink-probe");
match std::os::unix::fs::symlink(dir, &probe) {
Ok(_) => { let _ = fs::remove_file(&probe); true }
Err(_) => false,
}
} Try / catch
match result {
Err(e) if e.to_string().contains("No backup available to restore") => {
eprintln!("fresh install failed at symlink step; clear ~/.local/bin/but and retry: {e}");
}
other => other?,
} Prevention
- Ensure ~/.local/bin exists and is writable before first install
- Install on a local APFS volume, not SMB/NFS/exFAT mounts
- Clear any pre-existing `but` entry from other package managers
- After failure, manually `ln -s <app>/Contents/MacOS/gitbutler-tauri ~/.local/bin/but` as a workaround
When it happens
Trigger: install_app on a fresh install (no prior GitButler.app, install_app_backup absent) when unix_fs::symlink(&final_target, &but_symlink) fails - bin dir not writable, `but` path occupied by a file/directory, or the filesystem (e.g. some network mounts) does not support symlinks.
Common situations: Fresh machine with a sudo-created root-owned ~/.local/bin; `but` path pre-occupied by another tool; FAT/exFAT or SMB home mount lacking symlink support.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Failed to create symlink and failed to remove new…
- Failed to create symlink
- BUG: we do not create or work with symlinks
- Failed to create symlink
- Failed to install new version
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/ceee142d9a7ee34b.
Report an issue: GitHub.
Appendix: 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 58e5313667)