{"record":{"id":"52e1774513d8081f","repo":"gitbutlerapp/gitbutler","slug":"installation-failed-and-backup-restoration-also-fa","errorCode":null,"errorMessage":"Installation failed and backup restoration also failed - 'but' command may not work","messagePattern":"Installation failed and backup restoration also failed - 'but' command may not work","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/but-installer/src/install_linux.rs","lineNumber":119,"sourceCode":"    // a different mount point than persistent files\n    fs::copy(but_path, &install_bin_path)?;\n\n    let mut perms = fs::metadata(&install_bin_path)?.permissions();\n    perms.set_mode(0o755);\n    fs::set_permissions(&install_bin_path, perms)?;\n\n    if !validate_installed_binary(&install_bin_path) {\n        warn(\"Final installation verification failed\");\n\n        if let Some(but_backup) = but_backup {\n            warn(\"Attempting to restore backup\");\n            fs::rename(&but_backup, &install_bin_path)?;\n\n            if validate_installed_binary(&install_bin_path) {\n                info(\"Backup restored successfully, exiting ...\");\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\");\n        }\n    } else if let Some(but_backup) = but_backup {\n        info(&format!(\n            \"Removing backup at {}\",\n            but_backup.to_string_lossy()\n        ));\n        fs::remove_file(&but_backup)?;\n    }\n\n    Ok(())\n}\n","sourceCodeStart":101,"sourceCodeEnd":136,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/install_linux.rs#L101-L136","documentation":"Worst-case Linux rollback: the new binary failed post-install validation, the backup was renamed back into ~/.local/bin/but, but the restored binary also fails 'but --version'. The installer gives up and warns the but command may not work. This is a system-level execution problem, not a bad artifact - two independent binaries fail to run.","triggerScenarios":"Both old and new binaries fail to execute: ~/.local/bin mounted noexec, the system's glibc or dynamic loader broke independently (OS upgrade in progress), disk corruption, or endpoint security quarantining every newly written executable including the restore.","commonSituations":"noexec home partitions in hardened setups; distro upgrade replacing glibc mid-update; security software treating the rename-back as a new file and blocking it.","solutions":["Run ~/.local/bin/but --version directly and read the exact error (ENOEXEC, missing interpreter, 'Permission denied')","Check for noexec: findmnt -T ~/.local/bin/but -o OPTIONS; remount without noexec or move the bin dir","Restore endpoint-security allowance for ~/.local/bin/but, then reinstall","If unrecoverable, manually download the tarball and place the binary in an exec-mounted PATH directory"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Ensure the install destination can execute binaries before installing\nuse std::os::unix::fs::PermissionsExt;\nlet bin_dir = home.join(\".local/bin\");\nstd::fs::create_dir_all(&bin_dir)?;\nlet probe = bin_dir.join(\".exec-probe\");\nstd::fs::write(&probe, \"#!/bin/sh\\nexit 0\\n\")?;\nstd::fs::set_permissions(&probe, std::fs::Permissions::from_mode(0o755))?;\nlet exec_ok = std::process::Command::new(&probe).status().is_ok_and(|s| s.success());\nstd::fs::remove_file(&probe)?;\nanyhow::ensure!(exec_ok, \"install dir is not executable (noexec mount?)\");","typeGuard":null,"tryCatchPattern":"if let Err(e) = but_installer::run_installation_with_version(request, false) {\n    if e.to_string().contains(\"backup restoration also failed\") {\n        // both binaries fail: repair the environment (noexec mount, permissions, AV),\n        // then reinstall from scratch\n        repair_environment()?;\n        return but_installer::run_installation_with_version(\n            but_installer::VersionRequest::Release, false);\n    }\n    return Err(e);\n}","preventionTips":["Never mount ~/.local/bin noexec","Keep a copy of the last working but tarball for manual recovery","Probe binary execution in the install dir before running updates"],"tags":["rust","linux","rollback-failed","binary-validation","noexec","but-installer"],"backgroundTag":"installation-rollback","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}