Kuberwastaken/claurst · error
failed to install new binary
Error message
failed to install new binary: {} What it means
The in-place binary replacement failed: renaming/moving the new binary into the current executable's path errored (the formatted value is the underlying io error). On Windows the running exe must be sidelined first; failure typically means the file is locked by a running instance or the directory denies writes.
Solutions
- Close all running claurst instances and retry the upgrade
- Check write permissions on the install directory (may need elevated privileges)
- Delete leftover .exe.old / staging files that may block the rename, then re-run
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at src-rust/crates/cli/src/upgrade.rs:371 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/7a770bb50769b3b2.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/cli/src/upgrade.rs:371
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.path);
}
}
fn swap_binary(current: &Path, new: &Path) -> Result<()> {
#[cfg(target_os = "windows")]
{
// Windows holds an exclusive lock on the running .exe — we can rename
// it but not unlink it, so move-aside, then move-in-place.
let mut sidelined = current.to_path_buf();
sidelined.set_extension("exe.old");
let _ = std::fs::remove_file(&sidelined);
std::fs::rename(current, &sidelined)
.with_context(|| format!("failed to sideline current exe to {}", sidelined.display()))?;
if let Err(e) = std::fs::copy(new, current) {
// Try to roll back the rename so the user isn't left without claurst.
let _ = std::fs::rename(&sidelined, current);
bail!("failed to install new binary: {}", e);
}
// Best-effort cleanup of the old exe (Windows may keep it locked
// until the running process exits — that's fine).
let _ = std::fs::remove_file(&sidelined);
Ok(())
}
#[cfg(unix)]
{
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
// std::fs::copy() writes into the existing inode (open + O_TRUNC), and
// that inode is the running process's own text segment — the kernel
// rejects the write with ETXTBSY ("Text file busy"). rename() instead
// swaps the directory entry to point at a new inode, which the kernel
// allows even while the old inode is still mapped and executing.
// rename() requires src/dest on the same filesystem, so stage theView on GitHub (pinned to b0637c97ec)