{"record":{"id":"6f516a9ac85caaba","repo":"gitbutlerapp/gitbutler","slug":"installation-failed-but-your-previous-installation","errorCode":null,"errorMessage":"Installation failed but your previous installation was restored","messagePattern":"Installation failed but your previous installation was restored","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/install_linux.rs","lineNumber":117,"sourceCode":"    // NOTE: Must copy rather than rename. Rename assumes source and dest are on the same mount\n    // point, but /tmp on Linux systems is very often an in-memory file system (tmpfs) and thus on\n    // 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}","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-installer/src/install_linux.rs#L99-L135","documentation":"On Linux, after copying the new but binary into ~/.local/bin and chmod 755, install_linux runs 'but --version' to validate it. When that fails but a backup of the previous binary exists, the backup is renamed back and re-validated; if the restored copy passes, the installer bails with this message. Your previous version is intact and functional - the new one was rejected post-install.","triggerScenarios":"The newly downloaded binary fails to execute on this host - glibc older than the binary's requirements, wrong architecture, noexec mount on ~/.local/bin, truncated copy from a full disk, or endpoint security blocking newly written executables - while the previous binary still runs fine.","commonSituations":"Updating but on an old LTS distro (CentOS 7, Ubuntu 18.04) when a release raises its glibc baseline; corporate antivirus quarantining the new binary; ~/.local partition full during the copy.","solutions":["Confirm the old version still works: ~/.local/bin/but --version","Diagnose why the new binary fails: run it directly from a temp dir and read the loader error ('No such file or directory' from ld.so means the ELF interpreter/libs are too new for the host)","Check mount flags (findmnt ~/.local/bin -o OPTIONS) for noexec and disk space (df -h ~/.local /tmp)","Stay on the last compatible version or upgrade the OS / build but from source"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Pre-flight: the host must be able to load the new binary's shared libraries\nlet out = std::process::Command::new(\"ldd\").arg(&downloaded_but).output()?;\nlet ldd = String::from_utf8_lossy(&out.stdout);\nif ldd.contains(\"not found\") {\n    anyhow::bail!(\"host is missing shared libraries required by the new but binary\");\n}","typeGuard":null,"tryCatchPattern":"match but_installer::run_installation_with_version(request, false) {\n    Err(e) if e.to_string().contains(\"previous installation was restored\") => {\n        // system is functional on the old version; report and stop, do not retry blindly\n        log::warn!(\"update rejected; previous but version is still active\");\n    }\n    result => result,\n}","preventionTips":["Verify the host glibc/arch can run new artifacts before updating (ldd, uname -m)","Keep free disk space under ~/.local and /tmp","Allowlist ~/.local/bin/but with endpoint security before scripted updates"],"tags":["rust","linux","rollback","binary-validation","glibc","but-installer"],"backgroundTag":"installation-rollback","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}