gitbutlerapp/gitbutler · error
Failed to create symlink
Error message
Failed to create symlink: {e} - attempting to restore backup What it means
After moving the new app bundle into place, install_app attempts unix_fs::symlink(final_target, but_symlink). If symlink creation fails, the installer warns with the OS error and enters rollback: it restores the backed-up previous installation (install_app_backup) if present, otherwise bails. The message means the atomic install could not finish and the previous state is being recovered.
Solutions
- Re-run the installer with elevated privileges (sudo) or point it at a user-writable bin directory on PATH.
- Check what occupies the symlink path: `ls -la $(dirname $(which but))/but` and remove any conflicting directory/file.
- Verify free disk space and that the app bundle target (Contents/MacOS/gitbutler-tauri) exists in the installed .app.
- Check the printed error after 'Failed to create symlink:' for the underlying errno and fix accordingly (e.g. chown the bin dir).
Example fix
# before $ ./gitbutler-installer # fails: permission denied on /usr/local/bin # after $ sudo ./gitbutler-installer # or set install dir to ~/bin (on PATH)
Defensive patterns
Strategy: validation
Validate before calling
# Verify the bin dir is writable and the path is not occupied before installing. test -w /usr/local/bin || echo 'need sudo or a different install dir' [ -d /usr/local/bin/but ] && echo "conflict: /usr/local/bin/but is a directory"
Try / catch
// Wrap the installer run; treat non-zero exit as rollback failure candidate.
const res = spawnSync(installer, { stdio: 'inherit' });
if (res.status !== 0) {
console.error('Install failed; check rollback note and permissions on the target bin dir.');
} Prevention
- Install into a user-writable PATH directory (~/bin) when you lack sudo.
- Ensure the symlink destination path is not already a directory or immutable file.
- Keep disk space above a safe margin; symlink/bundle moves fail on a full disk.
- On managed Macs, pre-approve installer permissions with MDM.
When it happens
Trigger: download_and_install_app -> install_app on macOS when creating the 'but' symlink fails, typically because the bin directory is not writable (permissions, SIP-protected paths, the path is a directory rather than a symlink) or the target file does not exist.
Common situations: Installing into /usr/local/bin without sudo on a locked-down Mac; corporate MDM policies blocking symlink creation in PATH dirs; a leftover 'but' directory occupying the symlink path; disk full.
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
- A 'but' binary already exists at
- Failed to create symlink
- Failed to move new installation into place - restoring…
- Final installation verification failed - attempting to…
- Found existing 'but' symlink pointing to
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/31bcae047970ad0f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-installer/src/install_macos.rs:235
bail!(
"Failed to install new version: {e}. Previous installation restored successfully."
);
}
// No backup to restore, just fail
bail!("Failed to move new installation into place: {e}");
}
// Update the symlink to point to the new installation
let final_target = install_app.join("Contents/MacOS/gitbutler-tauri");
let _ = fs::remove_file(&but_symlink);
// Try to create symlink and verify - if either fails, rollback
let symlink_result = unix_fs::symlink(&final_target, &but_symlink);
let _ = fs::remove_file(&but_new);
if let Err(e) = symlink_result {
// 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 {View on GitHub (pinned to 58e5313667)