{"record":{"id":"bd6735b69f5eabac","repo":"gitbutlerapp/gitbutler","slug":"failed-to-create-symlink-e-previous-installati","errorCode":null,"errorMessage":"Failed to create symlink: {e}. Previous installation was restored.","messagePattern":"Failed to create symlink: (.+?)\\. Previous installation was restored\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":252,"sourceCode":"        // Symlink creation failed - rollback to backup\n        warn(&format!(\n            \"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\");","sourceCodeStart":234,"sourceCodeEnd":270,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/install_macos.rs#L234-L270","documentation":"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.","triggerScenarios":"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.","commonSituations":"A stray 'but' directory from a botched manual install; root-owned ~/.local/bin after running something with sudo; restored cleanly afterwards.","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"],"exampleFix":"# before: a directory blocks the symlink path\nls -ld ~/.local/bin/but   # drwxr-xr-x ...\nrm -rf ~/.local/bin/but\n# after\nbut-installer 0.18.7","handlingStrategy":"validation","validationCode":"// The 'but' link path must be absent or a removable file, never a directory\nlet but_link = home.join(\".local/bin/but\");\nif but_link.symlink_metadata().is_ok() {\n    anyhow::ensure!(!but_link.is_dir(),\n        \"~/.local/bin/but is a directory; remove it before reinstalling\");\n}","typeGuard":null,"tryCatchPattern":"match but_installer::run_installation_with_version(request, false) {\n    Err(e) if e.to_string().contains(\"Failed to create symlink\")\n        && e.to_string().contains(\"was restored\") =>\n    {\n        // old version intact; clear the link path and retry once\n        let _ = std::fs::remove_file(home.join(\".local/bin/but\"));\n        but_installer::run_installation_with_version(request, false)\n    }\n    result => result,\n}","preventionTips":["Never create a directory named 'but' in the PATH bin dir","Keep ~/.local/bin user-owned","Remove stale 'but' links before scripted updates"],"tags":["rust","macos","symlink","rollback-restored","but-installer"],"backgroundTag":"symlink-creation-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}