NousResearch/hermes-agent · error · anyhow::Error
Hermes is still running. Close all Hermes windows and try th
Error message
Hermes is still running. Close all Hermes windows and try the update again.
What it means
Stage-2 outcome of the update flow: `hermes update` exited with a status that maps to the 'still running' arm — the CLI refused because Hermes processes were detected alive. Before overwriting files the updater must have the old desktop app (and any Hermes sessions) shut down; the emitted stage 'update' is marked Failed with this message.
Source
Thrown at apps/bootstrap-installer/src-tauri/src/update.rs:454
Some(code) if code == UPDATE_EXIT_CONCURRENT => {
let msg = "Hermes is still running. Close all Hermes windows and try \
the update again."
.to_string();
emit_stage(
&app,
"update",
StageState::Failed,
Some(update_ms),
Some(msg.clone()),
);
emit(
&app,
BootstrapEvent::Failed {
stage: Some("update".into()),
error: msg.clone(),
},
);
return Err(anyhow!(msg));
}
other => {
let msg = format!(
"hermes update failed (exit {:?}). See {} for details.",
other,
crate::paths::hermes_home()
.join("logs")
.join("update.log")
.display()
);
emit_stage(
&app,
"update",
StageState::Failed,
Some(update_ms),
Some(msg.clone()),
);
emit(View on GitHub (pinned to c896c09c42)
Solutions
- Close all Hermes windows, tabs, and terminals running hermes, then retry the update.
- Check for lingering processes (`ps aux | grep -i hermes` / Task Manager) and end them.
- Retry — shutdown races are timing-dependent and usually succeed on a second attempt once processes are gone.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: no hermes processes should be alive before updating.
fn hermes_running() -> bool {
let out = if cfg!(target_os = "windows") {
std::process::Command::new("tasklist").args(["/FI", "IMAGENAME eq hermes.exe"]).output()
} else {
std::process::Command::new("pgrep").args(["-f", "hermes"]).output()
};
out.map(|o| !o.stdout.is_empty()).unwrap_or(true) // fail closed
}
if hermes_running() {
eprintln!("Close all Hermes windows/processes before updating.");
} Try / catch
// Treat as retryable, not fatal: prompt the user and retry the update once processes are gone.
match exit {
ExitCode::STILL_RUNNING => {
emit_stage(&app, "update", StageState::Failed, Some(ms), Some("Hermes is still running".into()));
// surface a retry affordance in the UI rather than a dead end
}
_ => { /* real failure: consult update.log */ }
} Prevention
- Close all Hermes windows, tabs, and terminal sessions before triggering the update.
- Have the updater wait longer / poll for process exit before declaring the race lost.
- Make dashboards that spawn updates shut their backend down first.
When it happens
Trigger: Running the updater while Hermes desktop windows, a dashboard tab backend, TUI sessions, or gateway processes are still alive; the stage-1 'wait for the old desktop to die' step timed out or raced a slow shutdown; a background hermes process (cron ticker, serve backend) survived the window close.
Common situations: User clicked update but left a dashboard tab open in a browser; an Electron main process took seconds to exit and the update started meanwhile; a stray `hermes serve` or gateway process from an earlier session is still running.
Related errors
- Another Hermes update is already running (PID {}, started {}
- Could not find the hermes CLI under {}. Is Hermes installed?
- hermes update failed (exit {:?}). See {} for details.
- Rebuilding the desktop app failed (exit {:?}). The update wa
- spawning {} {:?}: {e}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/27d2444cfac74f6a.
Report an issue: GitHub.