fix(update): GUI update self-deadlocks against its own lock — every retry fails with "Hermes is still running" - #74630
Merged
Merged
Conversation
…it already holds The cross-process update lock (fe8e4d9) made the in-progress marker mutually exclusive across every update entrypoint — but the Tauri updater holds that marker for its WHOLE run and then spawns hermes update as a child stage. The child read the marker, found its own parent's live pid, refused with exit 2, and the GUI mapped that to "Hermes is still running. Close all Hermes windows and try the update again." Retry spawns a fresh updater that deadlocks against itself the same way, so every GUI-driven update dead-ends on the failure screen with no winnable retry (observed: three consecutive self-refusals in bootstrap-installer.log within 90 seconds). Hand the claim off explicitly: update_child_env exports HERMES_UPDATE_HANDOFF_PID naming the updater's own pid, and UpdateLock.acquire treats a live holder matching that pid as the lock we are already running under — run without claiming, and release leaves the parent's marker untouched. The env var alone grants nothing: the pid must also be the live marker owner, so a stale or forged value cannot bypass the lock, and a dashboard-spawned hermes update (no handoff env) is still refused exactly as before.
OutThisLife
enabled auto-merge
July 30, 2026 05:56
Contributor
૮ >ﻌ< ა ci reviewran on 8c76fe1 ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence is publishing... |
4 tasks
1 task
1 task
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…tart-race fix(update): GUI update self-deadlocks against its own lock — every retry fails with "Hermes is still running"
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…tart-race fix(update): GUI update self-deadlocks against its own lock — every retry fails with "Hermes is still running"
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Any install whose checkout already carries the cross-process update lock (fe8e4d9, merged yesterday) self-deadlocks on its next GUI → Update Hermes: the Tauri updater claims the update-in-progress marker for its whole run, then spawns
hermes updateas a child stage — which reads the marker, finds its own parent's live pid, and refuses with exit 2. The GUI surfaces that as "Hermes is still running. Close all Hermes windows and try the update again", and Retry launches a fresh updater that deadlocks against itself the same way.The rollout shape hides it for one cycle: the child checks the lock from disk code before pulling, so the first update after fe8e4d9 landed still runs the pre-lock child and succeeds — it's the update after that which dead-ends. Observed exactly that way in
bootstrap-installer.log: a clean update at 04:44 UTC (the one that installed the lock code), then three consecutive self-refusals (PIDs 86193 → 86854 → 87252) starting 05:42, each refusing its own parent's marker.The fix hands the claim off explicitly instead of weakening the lock:
update_child_envexportsHERMES_UPDATE_HANDOFF_PIDnaming the updater's own pid, andUpdateLock.acquiretreats a live holder matching that pid as the lock we're already running under — the child runs without claiming, andreleaseleaves the parent's marker untouched for the remaining rebuild/install stages. The env var alone grants nothing: the pid must also be the live marker's owner, so a stale or forged value can't bypass the lock, and a dashboard-spawnedhermes update(no handoff env) is still refused exactly as the original fix intended.