{"record":{"id":"8994d9e55d4c6bf5","repo":"gitbutlerapp/gitbutler","slug":"failed-to-install-new-version-also-failed-to","errorCode":null,"errorMessage":"Failed to install new version: {}. Also failed to restore backup: {}. Your app may be at {}","messagePattern":"Failed to install new version: (.+?)\\. Also failed to restore backup: (.+?)\\. Your app may be at (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":210,"sourceCode":"\n    // Backup existing installation if it exists\n    let had_backup = install_app.exists();\n    if had_backup && let Err(e) = fs::rename(&install_app, &install_app_backup) {\n        // Failed to backup - clean up artifacts before failing\n        cleanup_artifacts();\n        return Err(e.into());\n    }\n\n    // Move new installation into place with rollback on failure\n    if let Err(e) = fs::rename(&install_app_new, &install_app) {\n        // Clean up stale artifacts before handling the error\n        cleanup_artifacts();\n\n        // Critical failure - restore backup if we created one\n        if had_backup && install_app_backup.exists() {\n            warn(\"Failed to move new installation into place - restoring backup\");\n            if let Err(restore_err) = fs::rename(&install_app_backup, &install_app) {\n                bail!(\n                    \"Failed to install new version: {}. Also failed to restore backup: {}. Your app may be at {}\",\n                    e,\n                    restore_err,\n                    install_app_backup.display()\n                );\n            }\n            bail!(\n                \"Failed to install new version: {e}. Previous installation restored successfully.\"\n            );\n        }\n        // No backup to restore, just fail\n        bail!(\"Failed to move new installation into place: {e}\");\n    }\n\n    // Update the symlink to point to the new installation\n    let final_target = install_app.join(\"Contents/MacOS/gitbutler-tauri\");\n    let _ = fs::remove_file(&but_symlink);\n","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/install_macos.rs#L192-L228","documentation":"Critical macOS rollback failure: fs::rename of the staged new .app into the install location failed, and the follow-up rename restoring the backup failed too. The message embeds the original rename error, the restore error, and the backup path where the previous app still sits. The install location may now be empty or partial, so manual recovery is expected.","triggerScenarios":"The swap rename fails because the target app bundle is running (macOS locks bundle executables), the install dir is not writable, or the disk is full - and the backup restore then fails for the same or a compounding reason (permissions, disk full, SIP-protected path).","commonSituations":"Updating while GitButler desktop app is open; non-admin user installing into /Applications; disk pressure during the double-size swap window.","solutions":["Quit GitButler completely (Cmd-Q) and retry the install","Manually restore from the printed backup path: mv '<backup path from the message>' /Applications/GitButler.app","Free disk space and fix permissions on the install dir, then rerun but-installer","If the backup path no longer exists, do a fresh install and treat the previous app as lost"],"exampleFix":"# recovery for the state after this error\nmv \"$(path printed after 'Your app may be at')\" /Applications/GitButler.app\nln -sf /Applications/GitButler.app/Contents/MacOS/gitbutler-tauri ~/.local/bin/but","handlingStrategy":"try-catch","validationCode":"// Before an update: the app must not be running, and space must be available\nlet running = std::process::Command::new(\"pgrep\")\n    .arg(\"-x\").arg(\"gitbutler-tauri\")\n    .stdout(std::process::Stdio::null())\n    .status().is_ok_and(|s| s.success());\nanyhow::ensure!(!running, \"GitButler is running; quit it before updating\");","typeGuard":null,"tryCatchPattern":"if let Err(e) = but_installer::run_installation_with_version(request, false) {\n    let msg = e.to_string();\n    if msg.contains(\"Also failed to restore backup\") {\n        // recover manually from the path printed after \"Your app may be at\"\n        let backup = msg.rsplit(\"Your app may be at \").next().unwrap_or_default();\n        recover_app_from_backup(std::path::Path::new(backup.trim()))?;\n    }\n    return Err(e);\n}","preventionTips":["Quit GitButler before running updates","Keep roughly 2x app-bundle size free on the install volume","Run the installer as the user who owns the install directory"],"tags":["rust","macos","rollback-failed","rename","disk-full","but-installer"],"backgroundTag":"installation-rollback","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}