{"record":{"id":"6c3a2c068a985428","repo":"astrid-runtime/astrid","slug":"detail-error","errorCode":null,"errorMessage":"{detail}: {error}","messagePattern":"\\{detail\\}: \\{error\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/astrid-core/src/platform_fs.rs","lineNumber":937,"sourceCode":"                            .push(format!(\"{}: {rollback_error}\", installed_live.display()));\n                    }\n                } else if let Err(rollback_error) = std::fs::remove_file(installed_live) {\n                    rollback_errors.push(format!(\"{}: {rollback_error}\", installed_live.display()));\n                }\n            }\n            for (remaining, _) in &staged[index..] {\n                let _ = std::fs::remove_file(remaining);\n            }\n            let detail = if rollback_errors.is_empty() {\n                format!(\"failed to install {}\", live.display())\n            } else {\n                format!(\n                    \"failed to install {}; rollback also failed ({}); restore *.bak manually\",\n                    live.display(),\n                    rollback_errors.join(\"; \")\n                )\n            };\n            return Err(io::Error::new(error.kind(), format!(\"{detail}: {error}\")));\n        }\n    }\n    Ok(())\n}\n\n#[cfg(test)]\n#[path = \"platform_fs/tests.rs\"]\nmod tests;\n","sourceCodeStart":919,"sourceCodeEnd":946,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-core/src/platform_fs.rs#L919-L946","documentation":"After staging, the installer renames each `.{name}.new` onto its live path. If a rename fails, the function rolls back already-installed files from `.bak` copies; this error wraps both the rename failure and the final detail message. If rollback also failed, the detail reads `failed to install <live>; rollback also failed (...); restore *.bak manually` — the installation may be in a mixed state and the user must restore backups by hand.","triggerScenarios":"`std::fs::rename(temporary, live)` fails — typically ETXTBSY (live executable still running on Linux), EACCES/EPERM (no permission to replace in install_dir), or the live target is held/immutable; rollback then also fails when `.bak` copies are missing, locked, or the directory became read-only.","commonSituations":"Self-updating a running CLI (ETXTBSY on Linux); another updater instance running concurrently; SELinux/AppArmor or read-only mounts blocking the rename; `.bak` files deleted by cleanup tools so rollback cannot restore.","solutions":["Stop all running instances of the executable (or update a copy not currently executing) and retry the update","Manually restore each `<name>.bak` over `<name>` in `install_dir` as the message instructs, then retry the update","Check and remove immutable flags / policy blocks (`chattr -i`, SELinux/AppArmor) on install_dir","Serialize updater runs with a lock file to avoid concurrent replacement attempts"],"exampleFix":"// before\napp.update_self()?; // app is currently running -> ETXTBSY\n// after\nif !current_exe_is_running_copy() {\n    app.update_self()?;\n} else {\n    spawn_detached_updater_and_exit();\n}","handlingStrategy":"try-catch","validationCode":"fn live_executables_idle(install_dir: &Path, names: &[&str]) -> bool {\n    !install_dir.join(\".running.lock\").exists()\n        && names.iter().all(|n| is_replaceable(&install_dir.join(n)))\n}\nfn is_replaceable(p: &Path) -> bool {\n    !p.exists() || std::fs::rename(p, p).is_ok()\n}","typeGuard":null,"tryCatchPattern":"match replace_executable_set(&install_dir, &extract_dir, names) {\n    Err(e) if e.to_string().contains(\"rollback also failed\") => {\n        eprintln!(\"MANUAL ACTION REQUIRED: restore <name>.bak over <name> in {}\", install_dir.display());\n        std::process::exit(1);\n    }\n    Err(e) => return Err(e.into()),\n    Ok(()) => {},\n}","preventionTips":["Never self-replace the exact binary that is executing; spawn a detached updater and exit first","Serialize update runs with an exclusive lock file","Keep .bak files until a successful post-update verification","Check for immutable flags / restrictive policies on install_dir before updating"],"tags":["filesystem","rename-failed","rollback","self-update","txtbsy"],"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-17T15:17:12.973Z"}