Bug Description
When the Hermes Desktop Electron process becomes a zombie/defunct (e.g. after a crash, OOM kill, or kill -9), the SingletonLock symlink in ~/.config/Hermes/ still points to the dead PID. The next launch via hermes desktop (or the .desktop shortcut) silently exits with code 0 — no error message, no window, no log entry indicating the problem. The user sees nothing happen.
Steps to Reproduce
- Launch
hermes desktop — it works, window appears
- Kill the Electron process abruptly:
kill -9 <hermes-electron-pid>
- The
SingletonLock symlink remains in ~/.config/Hermes/SingletonLock -> <hostname>-<dead-pid>
- Launch
hermes desktop again (or click the .desktop shortcut)
- Nothing happens. The process exits immediately with code 0. No window, no error.
Expected Behavior
The app should detect the stale SingletonLock (PID is dead), clean it up, and launch normally. Or at minimum, log a message in desktop.log indicating the lock failure so the user can diagnose it.
Actual Behavior
The process exits silently with code 0. The desktop.log shows the backend boot completing successfully, then nothing — no error about the lock:
[hermes] [boot] Hermes backend is ready. Finalizing desktop startup
No further log entries. The Electron process quits because requestSingleInstanceLock() returned false, but this is not logged anywhere.
Affected Component
- Other (Desktop / Electron app)
Operating System
Ubuntu 24.04, kernel 7.0.0-28-generic, GNOME on X11
Python Version
3.11.15
Hermes Version
0.19.1 (upstream 91937a6, local b1858f3, install method: git)
Debug Report
hermes debug share --local output (not uploaded to paste service to avoid exposing personal data from session logs):
version: 0.19.1 [b1858f33] (2026-07-31)
os: Linux 7.0.0-28-generic x86_64
python: 3.11.15
openai_sdk: 2.24.0
profile: default
hermes_home: ~/.hermes
model: glm-5.2
provider: ollama-cloud
terminal: local
features:
toolsets: hermes-cli, web
mcp_servers: 0
memory_provider: built-in
gateway: running (docker (foreground), pid 1400)
platforms: none
cron_jobs: 0
skills: 129
config_overrides:
agent.max_turns: 900
display.streaming: True
display.show_reasoning: False
toolsets: [hermes-cli, web]
Additional Logs
~/.hermes/logs/desktop.log — repeated boot sequences showing the backend starting fine but the Electron process exiting silently:
[hermes] [boot] Resolving Hermes backend
[hermes] [boot] Hermes runtime is ready
[hermes] [boot] Starting Hermes backend via Hermes at /home/jr0237/.hermes/hermes-agent
[hermes] HERMES_BACKEND_READY port=43543
[hermes] Hermes backend listening on 127.0.0.1:43543
[hermes] [boot] Hermes backend is ready. Finalizing desktop startup
# ← process exits here, no further log entries, no error
The SingletonLock state observed:
$ ls -la ~/.config/Hermes/SingletonLock
lrwxrwxrwx 1 jr0237 jr0237 20 ago 3 20:44 ~/.config/Hermes/SingletonLock -> jr0237-MS-7A38-86682
# PID 86682 was a zombie/defunct Hermes Electron process
Root Cause Analysis
In apps/desktop/electron/main.ts (line ~11628):
const _gotSingleInstanceLock = app.requestSingleInstanceLock()
if (!_gotSingleInstanceLock) {
app.quit()
}
Electron's requestSingleInstanceLock() on Linux creates a SingletonLock symlink in the user data dir (~/.config/Hermes/). When the lock exists but points to a dead PID, Electron can still treat it as a valid lock on some X11/Linux setups — requestSingleInstanceLock() returns false, and the app calls app.quit() immediately with no user feedback.
The second-instance handler (line ~11633) never fires because there IS no running first instance — the lock is stale but the process behind it is dead.
The focusWindow function (line ~8645) handles minimized/invisible windows but is never called because the app quits before reaching whenReady().
Proposed Fix
Electron's requestSingleInstanceLock() is known to leave stale locks on Linux when the process dies abnormally. Options:
-
Before calling app.quit() on lock failure, check if the PID in the SingletonLock symlink target is actually alive. If the PID is dead, remove the stale lock files (SingletonLock, SingletonCookie, SingletonSocket) and retry requestSingleInstanceLock(). This is the approach used by VS Code and other Electron apps.
-
At startup, proactively validate any existing SingletonLock — if it points to a dead PID, clean it up before attempting to acquire the lock.
-
Log a message when requestSingleInstanceLock() returns false so the failure is visible in desktop.log (currently completely silent).
Are you willing to submit a PR for this?
- I'd like to fix this myself and submit a PR
Bug Description
When the Hermes Desktop Electron process becomes a zombie/defunct (e.g. after a crash, OOM kill, or
kill -9), theSingletonLocksymlink in~/.config/Hermes/still points to the dead PID. The next launch viahermes desktop(or the.desktopshortcut) silently exits with code 0 — no error message, no window, no log entry indicating the problem. The user sees nothing happen.Steps to Reproduce
hermes desktop— it works, window appearskill -9 <hermes-electron-pid>SingletonLocksymlink remains in~/.config/Hermes/SingletonLock -> <hostname>-<dead-pid>hermes desktopagain (or click the.desktopshortcut)Expected Behavior
The app should detect the stale SingletonLock (PID is dead), clean it up, and launch normally. Or at minimum, log a message in
desktop.logindicating the lock failure so the user can diagnose it.Actual Behavior
The process exits silently with code 0. The
desktop.logshows the backend boot completing successfully, then nothing — no error about the lock:No further log entries. The Electron process quits because
requestSingleInstanceLock()returnedfalse, but this is not logged anywhere.Affected Component
Operating System
Ubuntu 24.04, kernel 7.0.0-28-generic, GNOME on X11
Python Version
3.11.15
Hermes Version
0.19.1 (upstream 91937a6, local b1858f3, install method: git)
Debug Report
hermes debug share --localoutput (not uploaded to paste service to avoid exposing personal data from session logs):Additional Logs
~/.hermes/logs/desktop.log— repeated boot sequences showing the backend starting fine but the Electron process exiting silently:The
SingletonLockstate observed:Root Cause Analysis
In
apps/desktop/electron/main.ts(line ~11628):Electron's
requestSingleInstanceLock()on Linux creates aSingletonLocksymlink in the user data dir (~/.config/Hermes/). When the lock exists but points to a dead PID, Electron can still treat it as a valid lock on some X11/Linux setups —requestSingleInstanceLock()returnsfalse, and the app callsapp.quit()immediately with no user feedback.The
second-instancehandler (line ~11633) never fires because there IS no running first instance — the lock is stale but the process behind it is dead.The
focusWindowfunction (line ~8645) handles minimized/invisible windows but is never called because the app quits before reachingwhenReady().Proposed Fix
Electron's
requestSingleInstanceLock()is known to leave stale locks on Linux when the process dies abnormally. Options:Before calling
app.quit()on lock failure, check if the PID in theSingletonLocksymlink target is actually alive. If the PID is dead, remove the stale lock files (SingletonLock,SingletonCookie,SingletonSocket) and retryrequestSingleInstanceLock(). This is the approach used by VS Code and other Electron apps.At startup, proactively validate any existing
SingletonLock— if it points to a dead PID, clean it up before attempting to acquire the lock.Log a message when
requestSingleInstanceLock()returnsfalseso the failure is visible indesktop.log(currently completely silent).Are you willing to submit a PR for this?