{"record":{"id":"088fb38d5667ad79","repo":"NousResearch/hermes-agent","slug":"installing-updated-app-at-err","errorCode":null,"errorMessage":"installing updated app at {}: {err}","messagePattern":"installing updated app at (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"apps/bootstrap-installer/src-tauri/src/update.rs","lineNumber":1100,"sourceCode":"            // bail — a failed update must not brick the install.\n            remove_dir_if_exists(tmp).await;\n            return Err(anyhow!(\n                \"could not move existing app aside at {} (leaving it in place): {err}\",\n                target.display()\n            ));\n        }\n        true\n    } else {\n        false\n    };\n    if let Err(err) = tokio::fs::rename(tmp, target).await {\n        // Restore the original app from the backup so the user keeps a working\n        // install, and clean up the staged copy.\n        if moved_old {\n            let _ = tokio::fs::rename(old, target).await;\n        }\n        remove_dir_if_exists(tmp).await;\n        return Err(anyhow!(\"installing updated app at {}: {err}\", target.display()));\n    }\n    remove_dir_if_exists(old).await;\n    Ok(())\n}\n\n#[cfg(not(target_os = \"macos\"))]\nasync fn install_macos_app_update(\n    _app: &AppHandle,\n    _install_root: &Path,\n    target_app: &Path,\n) -> Result<PathBuf> {\n    Ok(target_app.to_path_buf())\n}\n\nasync fn remove_dir_if_exists(path: &Path) {\n    if path.exists() {\n        let _ = tokio::fs::remove_dir_all(path).await;\n    }","sourceCodeStart":1082,"sourceCodeEnd":1118,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/apps/bootstrap-installer/src-tauri/src/update.rs#L1082-L1118","documentation":"Second phase of swap_in_new_bundle: the staged tmp bundle could not be renamed onto the target path. The updater then restores the original from the .hermes-update-old backup (best-effort), cleans up tmp, and errors — preserving the invariant that the target always points at a working bundle, either rolled back or untouched.","triggerScenarios":"Disk full so the rename cannot complete; target path recreated by another process between the two renames (losing the exclusive slot); cross-device rename (tmp staged on a different volume than target); SIP/permissions blocking writes to the final path.","commonSituations":"Target volume ran out of space mid-update; a second updater instance raced the swap; tmp and target on different mounts (e.g. target in /Applications on the system disk while HERMES_HOME staging sits on an external volume).","solutions":["Free space on the target volume and retry — rollback has already restored the old app, so the install is safe.","Ensure no other update/process is touching the target path (see the update-lock error [545]).","Keep HERMES_HOME and the target .app on the same volume so the swap renames stay same-filesystem.","If the old app was not restored (moved_old was false), re-run the installer to lay down a fresh app."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Ensure tmp and target are on the same filesystem so the final rename is atomic.\nfn same_volume(a: &std::path::Path, b: &std::path::Path) -> bool {\n    match (std::fs::metadata(a), std::fs::metadata(b)) {\n        (Ok(ma), Ok(mb)) => ma.dev() == mb.dev(),\n        _ => false,\n    }\n}\n// std::os::unix::fs::MetadataExt for dev(); stage tmp next to target, which the code already does.","typeGuard":null,"tryCatchPattern":"// Already correct: roll the original back from `old` before erroring, and clean tmp.\nif let Err(err) = tokio::fs::rename(tmp, target).await {\n    if moved_old {\n        let _ = tokio::fs::rename(old, target).await; // restore working bundle\n    }\n    remove_dir_if_exists(tmp).await;\n    return Err(anyhow!(\"installing updated app at {}: {err} (original restored)\", target.display()));\n}","preventionTips":["Free target-volume disk space before updating — the swap needs headroom for the rename.","Guarantee single-flight updates (see [545]) so nothing recreates the target path mid-swap.","Keep HERMES_HOME and the installed .app on the same volume."],"tags":["macos","filesystem","atomic-swap","update","bootstrap-installer"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}