{"record":{"id":"789ae7c787850d50","repo":"astrid-runtime/astrid","slug":"failed-to-stage-error","errorCode":null,"errorMessage":"failed to stage {}: {error}","messagePattern":"failed to stage (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-core/src/platform_fs.rs","lineNumber":901,"sourceCode":"\n    let mut staged = Vec::new();\n    for name in names {\n        let temporary = install_dir.join(format!(\".{name}.new\"));\n        let stage_result = (|| -> io::Result<()> {\n            std::fs::copy(extract_dir.join(name), &temporary)?;\n            #[cfg(unix)]\n            {\n                use std::os::unix::fs::PermissionsExt as _;\n                std::fs::set_permissions(&temporary, std::fs::Permissions::from_mode(0o755))?;\n            }\n            Ok(())\n        })();\n        if let Err(error) = stage_result {\n            let _ = std::fs::remove_file(&temporary);\n            for (staged_temporary, _) in &staged {\n                let _ = std::fs::remove_file(staged_temporary);\n            }\n            return Err(io::Error::new(\n                error.kind(),\n                format!(\"failed to stage {}: {error}\", temporary.display()),\n            ));\n        }\n        staged.push((temporary, install_dir.join(name)));\n    }\n\n    for (index, (temporary, live)) in staged.iter().enumerate() {\n        if let Err(error) = std::fs::rename(temporary, live) {\n            let mut rollback_errors = Vec::new();\n            for (_, installed_live) in &staged[..index] {\n                if let Some((_, backup)) = backups\n                    .iter()\n                    .find(|(backup_live, _)| backup_live == installed_live)\n                {\n                    if let Err(rollback_error) = std::fs::rename(backup, installed_live) {\n                        rollback_errors\n                            .push(format!(\"{}: {rollback_error}\", installed_live.display()));","sourceCodeStart":883,"sourceCodeEnd":919,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs.rs#L883-L919","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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"],"exampleFix":"// before\nreplace_executable_set(&Path::new(\"/usr/local/bin\"), &extract_dir, names)?; // EACCES\n// after\nlet install_dir = user_writable_bin_dir(); // e.g. ~/.local/bin\nreplace_executable_set(&install_dir, &extract_dir, names)?;","handlingStrategy":"try-catch","validationCode":"if !install_dir.is_dir() {\n    return Err(anyhow!(\"install dir missing\"));\n}\nif std::fs::metadata(install_dir)?.permissions().readonly() {\n    return Err(anyhow!(\"install dir is read-only\"));\n}\nif fs4::available_space(install_dir).unwrap_or(0) < min_required_bytes {\n    return Err(anyhow!(\"insufficient disk space\"));\n}","typeGuard":null,"tryCatchPattern":"match replace_executable_set(&install_dir, &extract_dir, names) {\n    Err(e) => {\n        match e.raw_os_error() {\n            Some(libc::ENOSPC) => eprintln!(\"disk full; free space and retry\"),\n            Some(libc::EACCES) | Some(libc::EPERM) => eprintln!(\"need write permission on install dir\"),\n            _ => eprintln!(\"staging failed: {e}\"),\n        }\n    }\n    Ok(()) => {},\n}","preventionTips":["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"],"tags":["filesystem","staging","copy-failed","permissions","self-update"],"backgroundTag":"file-write-failed","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}