NousResearch/hermes-agent · error · anyhow::Error

installing updated app at {}: {err}

Error message

installing updated app at {}: {err}

What it means

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.

Source

Thrown at apps/bootstrap-installer/src-tauri/src/update.rs:1100

            // bail — a failed update must not brick the install.
            remove_dir_if_exists(tmp).await;
            return Err(anyhow!(
                "could not move existing app aside at {} (leaving it in place): {err}",
                target.display()
            ));
        }
        true
    } else {
        false
    };
    if let Err(err) = tokio::fs::rename(tmp, target).await {
        // Restore the original app from the backup so the user keeps a working
        // install, and clean up the staged copy.
        if moved_old {
            let _ = tokio::fs::rename(old, target).await;
        }
        remove_dir_if_exists(tmp).await;
        return Err(anyhow!("installing updated app at {}: {err}", target.display()));
    }
    remove_dir_if_exists(old).await;
    Ok(())
}

#[cfg(not(target_os = "macos"))]
async fn install_macos_app_update(
    _app: &AppHandle,
    _install_root: &Path,
    target_app: &Path,
) -> Result<PathBuf> {
    Ok(target_app.to_path_buf())
}

async fn remove_dir_if_exists(path: &Path) {
    if path.exists() {
        let _ = tokio::fs::remove_dir_all(path).await;
    }

View on GitHub (pinned to c896c09c42)

Solutions

  1. Free space on the target volume and retry — rollback has already restored the old app, so the install is safe.
  2. Ensure no other update/process is touching the target path (see the update-lock error [545]).
  3. Keep HERMES_HOME and the target .app on the same volume so the swap renames stay same-filesystem.
  4. If the old app was not restored (moved_old was false), re-run the installer to lay down a fresh app.
Defensive patterns

Strategy: fallback

Validate before calling

// Ensure tmp and target are on the same filesystem so the final rename is atomic.
fn same_volume(a: &std::path::Path, b: &std::path::Path) -> bool {
    match (std::fs::metadata(a), std::fs::metadata(b)) {
        (Ok(ma), Ok(mb)) => ma.dev() == mb.dev(),
        _ => false,
    }
}
// std::os::unix::fs::MetadataExt for dev(); stage tmp next to target, which the code already does.

Try / catch

// Already correct: roll the original back from `old` before erroring, and clean tmp.
if let Err(err) = tokio::fs::rename(tmp, target).await {
    if moved_old {
        let _ = tokio::fs::rename(old, target).await; // restore working bundle
    }
    remove_dir_if_exists(tmp).await;
    return Err(anyhow!("installing updated app at {}: {err} (original restored)", target.display()));
}

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/088fb38d5667ad79. Report an issue: GitHub.