{"record":{"id":"2770059f00144b18","repo":"gitbutlerapp/gitbutler","slug":"failed-to-move-new-installation-into-place-resto","errorCode":null,"errorMessage":"Failed to move new installation into place - restoring backup","messagePattern":"Failed to move new installation into place - restoring backup","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/but-installer/src/install_macos.rs","lineNumber":208,"sourceCode":"        let _ = fs::remove_file(&but_new);\n    };\n\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\");","sourceCodeStart":190,"sourceCodeEnd":226,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/install_macos.rs#L190-L226","documentation":"install_app on macOS moves the staged new .app bundle into /Applications with fs::rename. When that rename fails, the installer warns that it is restoring the backup of the previous installation, then tries rename(backup, install_app). If the restore also fails it bails with a combined message naming both errors and where the backup lives.","triggerScenarios":"Raised in install_app (called from download_and_install_app) when fs::rename(&install_app_new, &install_app) fails — e.g. /Applications/App.app is locked by a running process, or the destination sits on a different volume so rename must copy cross-device and fails.","commonSituations":"The app is running and macOS holds the bundle open; permission issues on /Applications without admin rights; the target volume differs from the temp dir (cross-filesystem rename not supported); antivirus/quarantine tooling locking the bundle.","solutions":["Quit the running app (and any helper processes) and retry the install.","Re-run the installer with elevated privileges (sudo) so it can replace the bundle in /Applications.","Check that the backup path printed in the bail message still contains your old app and restore it manually if needed.","Ensure temp staging and /Applications are on the same volume, or copy instead of rename when crossing devices.","Free disk space if the rename failed due to insufficient space during cross-device copy."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight checks before install\nimport subprocess, os\ndef can_install(app_path):\n    if os.path.exists(app_path):\n        try:\n            os.rename(app_path, app_path + '.probe')\n            os.rename(app_path + '.probe', app_path)\n        except OSError as e:\n            return False, f'Cannot rename target: {e}'\n    return os.access(os.path.dirname(app_path), os.W_OK), None","typeGuard":null,"tryCatchPattern":"// Rust pattern: check rename result and preserve backup path on failure\nif let Err(e) = fs::rename(&install_app_new, &install_app) {\n    if let Err(re) = fs::rename(&install_app_backup, &install_app) {\n        bail!(\"install failed: {e}; restore failed: {re}; backup at {}\", install_app_backup.display());\n    }\n}","preventionTips":["Quit the app before upgrading so the bundle is not locked","Ensure /Applications is writable (admin rights) and the temp dir is on the same volume","Keep enough free disk space for both old and new bundles","Never delete the .backup bundle until the new version is verified"],"tags":["macos","installer","filesystem","rename"],"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"}