{"record":{"id":"ceee142d9a7ee34b","repo":"gitbutlerapp/gitbutler","slug":"failed-to-create-symlink-e-no-backup-available","errorCode":null,"errorMessage":"Failed to create symlink: {e}. No backup available to restore.","messagePattern":"Failed to create symlink: (.+?)\\. No backup available to restore\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":254,"sourceCode":"            \"Failed to create symlink: {e} - attempting to restore backup\"\n        ));\n        if install_app_backup.exists() {\n            if let Err(remove_err) = fs::remove_dir_all(&install_app) {\n                bail!(\n                    \"Failed to create symlink and failed to remove new installation during rollback: {}. Backup at: {}\",\n                    remove_err,\n                    install_app_backup.display()\n                );\n            }\n            fs::rename(&install_app_backup, &install_app)?;\n\n            let restored_target = install_app.join(\"Contents/MacOS/gitbutler-tauri\");\n            let _ = fs::remove_file(&but_symlink);\n            let _ = unix_fs::symlink(&restored_target, &but_symlink);\n\n            bail!(\"Failed to create symlink: {e}. Previous installation was restored.\");\n        } else {\n            bail!(\"Failed to create symlink: {e}. No backup available to restore.\");\n        }\n    }\n\n    if !validate_installed_binary(&but_symlink) {\n        // Try to restore backup\n        warn(\"Final installation verification failed - attempting to restore backup\");\n        if install_app_backup.exists() {\n            fs::remove_dir_all(&install_app)?;\n            fs::rename(&install_app_backup, &install_app)?;\n\n            let restored_target = install_app.join(\"Contents/MacOS/gitbutler-tauri\");\n            let _ = fs::remove_file(&but_symlink);\n            unix_fs::symlink(&restored_target, &but_symlink)?;\n\n            if validate_installed_binary(&but_symlink) {\n                success(\"Backup was restored successfully\");\n                bail!(\"Installation failed but your previous installation was restored\");\n            } else {","sourceCodeStart":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/install_macos.rs#L236-L272","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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`"],"exampleFix":"// before\nunix_fs::symlink(&final_target, &but_symlink)?;\n// after: caller-side check before install\nlet link = home.join(\".local/bin/but\");\nif let Ok(m) = fs::symlink_metadata(&link) {\n    if !m.file_type().is_symlink() {\n        bail!(\"{} exists and is not a symlink - move it first\", link.display());\n    }\n}","handlingStrategy":"validation","validationCode":"let bin = home.join(\".local/bin\");\nlet link = bin.join(\"but\");\nif !bin.exists() {\n    fs::create_dir_all(&bin)?;\n}\nif let Ok(m) = fs::symlink_metadata(&link) {\n    if !m.file_type().is_symlink() {\n        bail!(\"{} blocks the installer - remove it first\", link.display());\n    }\n}\n// sanity: symlinks supported on this filesystem\nlet probe = bin.join(\".symlink-probe\");\nstd::os::unix::fs::symlink(&bin.join(\".\"), &probe)?;\nlet _ = fs::remove_file(&probe);","typeGuard":"fn symlink_supported(dir: &Path) -> bool {\n    let probe = dir.join(\".symlink-probe\");\n    match std::os::unix::fs::symlink(dir, &probe) {\n        Ok(_) => { let _ = fs::remove_file(&probe); true }\n        Err(_) => false,\n    }\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"No backup available to restore\") => {\n        eprintln!(\"fresh install failed at symlink step; clear ~/.local/bin/but and retry: {e}\");\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["symlink","filesystem","installation","fresh-install"],"backgroundTag":"file-write-failed","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}