astrid-runtime/astrid · error
failed to stage {}: {error}
Error message
failed to stage {}: {error} What it means
During `replace_executable_set_by_rename`, each new executable is staged as `.{name}.new` inside `install_dir` (copied from `extract_dir`, chmod 0o755 on Unix). If any staging step fails, previously staged temporaries are cleaned up and the original OS error is re-raised with the temporary path prefixed: `failed to stage <path>: <error>`. Nothing live has been replaced yet, so the installation is untouched.
Source
Thrown at crates/astrid-core/src/platform_fs.rs:901
let mut staged = Vec::new();
for name in names {
let temporary = install_dir.join(format!(".{name}.new"));
let stage_result = (|| -> io::Result<()> {
std::fs::copy(extract_dir.join(name), &temporary)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt as _;
std::fs::set_permissions(&temporary, std::fs::Permissions::from_mode(0o755))?;
}
Ok(())
})();
if let Err(error) = stage_result {
let _ = std::fs::remove_file(&temporary);
for (staged_temporary, _) in &staged {
let _ = std::fs::remove_file(staged_temporary);
}
return Err(io::Error::new(
error.kind(),
format!("failed to stage {}: {error}", temporary.display()),
));
}
staged.push((temporary, install_dir.join(name)));
}
for (index, (temporary, live)) in staged.iter().enumerate() {
if let Err(error) = std::fs::rename(temporary, live) {
let mut rollback_errors = Vec::new();
for (_, installed_live) in &staged[..index] {
if let Some((_, backup)) = backups
.iter()
.find(|(backup_live, _)| backup_live == installed_live)
{
if let Err(rollback_error) = std::fs::rename(backup, installed_live) {
rollback_errors
.push(format!("{}: {rollback_error}", installed_live.display()));View on GitHub (pinned to affd8760f4)
Solutions
- Check disk space (`df -h`) and free space on the install volume, then retry
- Ensure the process has write permission to `install_dir` (run with sufficient privileges or install to a user-writable location)
- Confirm the source file in `extract_dir` still exists and is readable at staging time; re-extract if it vanished
- Exclude `install_dir` from antivirus/backup interference or close handles holding the `.new` file
Example fix
// before
replace_executable_set(&Path::new("/usr/local/bin"), &extract_dir, names)?; // EACCES
// after
let install_dir = user_writable_bin_dir(); // e.g. ~/.local/bin
replace_executable_set(&install_dir, &extract_dir, names)?; Defensive patterns
Strategy: try-catch
Validate before calling
if !install_dir.is_dir() {
return Err(anyhow!("install dir missing"));
}
if std::fs::metadata(install_dir)?.permissions().readonly() {
return Err(anyhow!("install dir is read-only"));
}
if fs4::available_space(install_dir).unwrap_or(0) < min_required_bytes {
return Err(anyhow!("insufficient disk space"));
} Try / catch
match replace_executable_set(&install_dir, &extract_dir, names) {
Err(e) => {
match e.raw_os_error() {
Some(libc::ENOSPC) => eprintln!("disk full; free space and retry"),
Some(libc::EACCES) | Some(libc::EPERM) => eprintln!("need write permission on install dir"),
_ => eprintln!("staging failed: {e}"),
}
}
Ok(()) => {},
} Prevention
- Check free disk space before updating
- Ensure the updater runs with write access to install_dir
- Keep extract sources present until staging completes
- Disable AV/backup interference with .new temp files
When it happens
Trigger: `std::fs::copy(extract_dir/name, install_dir/.name.new)` fails — typically ENOSPC (disk full on install_dir's volume), EACCES (no write permission in install_dir), or the extract source disappeared between validation and staging; `set_permissions(0o755)` failing for the same permission reasons.
Common situations: Install directory on a full or read-only volume (e.g. `/usr/local/bin` requiring root); antivirus or backup software locking/removing the temp file mid-copy; running the updater without elevated privileges after installing system-wide.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- {install_dir} is not writable — re-run with elevated permiss
- capsules are installed, but granting capsule access failed:
- mountpoint ancestor is writable without sticky protection: {
- mountpoint must be owned by the current OS user: {}
- mountpoint must be owner-private: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/789ae7c787850d50.
Report an issue: GitHub.