{"record":{"id":"3aa4533e3425d943","repo":"gitbutlerapp/gitbutler","slug":"final-installation-verification-failed-attempting-to-restore","errorCode":null,"errorMessage":"Final installation verification failed - attempting to restore backup","messagePattern":"Final installation verification failed - attempting to restore backup","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":260,"sourceCode":"                    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 {\n                bail!(\n                    \"Installation failed and backup restoration also failed - 'but' command may not work\"\n                );\n            }\n        } else {\n            bail!(\"Installation failed and no backup available to restore\");","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/install_macos.rs#L242-L278","documentation":"After the symlink is created, install_app calls validate_installed_binary(&but_symlink) to confirm the installed binary actually runs. If validation fails, the installer warns and rolls back: it removes the new install dir, renames the backup back into place, and re-points (or removes) the symlink. This guards against shipping a broken binary that would leave the user with a non-functional 'but' command.","triggerScenarios":"download_and_install_app -> install_app on macOS when the freshly installed binary at but_symlink fails validate_installed_binary - e.g. the downloaded .app is corrupted, the binary lacks the executable bit, is unsigned/quarantined and fails to spawn, or the architecture does not match (x86_64 binary on arm64 without Rosetta).","commonSituations":"Interrupted/partial download producing a corrupt .app; Gatekeeper blocking an unnotarized binary so the spawn check fails; wrong-architecture artifact; antivirus quarantining gitbutler-tauri.","solutions":["Re-download and re-run the installer to replace a possibly corrupted artifact.","Clear the quarantine attribute (`xattr -dr com.apple.quarantine /Applications/GitButler.app`) and retry if Gatekeeper blocked execution.","Verify you downloaded the artifact matching your CPU architecture (arm64 vs x86_64) or install Rosetta 2.","Check Console.app / security logs for what killed the binary during validation, then address (codesign, AV exclusion)."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"# Validate the artifact before install: run the binary directly.\n/usr/sbin/file '/Applications/GitButler.app/Contents/MacOS/gitbutler-tauri'\nxattr -l /Applications/GitButler.app | grep -i quarantine","typeGuard":null,"tryCatchPattern":"const res = spawnSync(installer, { stdio: 'inherit' });\nif (res.status !== 0 && fs.existsSync('/Applications/GitButler.app')) {\n  spawnSync('xattr', ['-dr', 'com.apple.quarantine', '/Applications/GitButler.app']);\n  // retry the install once\n}","preventionTips":["Download installers over stable network connections; re-download if checksum differs.","Match the artifact to your architecture (arm64 vs x86_64) and install Rosetta if needed.","Pre-approve/notarize binaries in corporate environments that block unsigned executables.","Exclude the install directory from antivirus quarantine heuristics."],"tags":["installer","macos","verification","rollback","binary"],"backgroundTag":"installation-verification-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"}