Skip to content

[Bug]: Windows: \hermes update always reports "Another hermes.exe is running" — launcher shim PID not excluded from concurrent-instance detection #29341

@Nodejs2233

Description

@Nodejs2233

Bug Description

On Windows, hermes update always fails with Another hermes.exe is running: PID <X> hermes.exe, even when no other Hermes process exists on the system. The reported PID belongs to the very hermes.exe
console-script launcher that started the current update invocation. hermes update --force is the only way through, and it works cleanly — confirming nothing else is actually holding the venv shim.

Environment

  • OS: Windows 11 Enterprise 22H2 (10.0.22621)
  • Shell: Git Bash 2.x and PowerShell 5.1 (reproduces in both)
  • Hermes Agent: v0.14.0 (2026.5.16) (also reproduced on builds prior to this)
  • Python: 3.11.15 (venv at D:\AI\hermes\hermes-agent\venv)
  • Install path: D:\AI\hermes\hermes-agent (non-default — README's default is %LOCALAPPDATA%\hermes, but the install script accepted this location and hermes update works under --force, so the
    path itself is not the issue)
  • Hermes Desktop: NOT installed
  • No WSL2 involved — pure native Windows install

Reproduction

  1. Confirm zero Hermes-related processes are alive:
    Get-CimInstance Win32_Process | Where-Object {
        $_.Name -like '*hermes*' -or $_.ExecutablePath -like '*hermes*'
    }
    # returns nothing
    Get-Process python,pythonw -ErrorAction SilentlyContinue
    # returns nothing
  2. Confirm gateway is stopped (hermes gateway stop is a no-op).
  3. Run hermes update from a fresh shell.
  4. Output:
    ? Another hermes.exe is running:
    PID 18608 hermes.exe
Updating now would fail to overwrite D:\AI\hermes\hermes-agent\venv\Scripts\hermes.exe because
Windows blocks REPLACE on a running executable.

Close Hermes Desktop, exit any open `hermes` REPLs, and
stop the gateway (`hermes gateway stop`) before retrying.
Override with `hermes update --force` if you've already
confirmed those processes will not write to the venv.
  1. Immediately after exit, PID 18608 is no longer alive (Get-CimInstance Win32_Process -Filter "ProcessId=18608" returns nothing) — the "concurrent" process was the parent launcher, which exited together
    with the failed update.
  2. hermes update --force then succeeds and updates cleanly. Re-running plain hermes update reproduces the failure with a new PID every time.

Root cause (suspected)

hermes_cli/main.py:7256 _detect_concurrent_hermes_instances excludes only os.getpid(). On Windows, hermes.exe is a distlib-generated console-script launcher (Scripts\hermes.exe). Its runtime model:

  1. User runs hermes update → hermes.exe launcher process starts (this is the PID later reported as "concurrent", e.g. 18608).
  2. Launcher spawns a child python.exe -m hermes_cli ... and stays alive, waiting on the child.
  3. Detection runs inside the child Python process. os.getpid() returns the Python process PID, not the launcher PID.
  4. psutil.process_iter sees the launcher's exe resolves to the same path as Scripts\hermes.exe, the launcher PID is not in exclude_pid, so it is reported as "another hermes.exe is running".

The doc-comment block above the function calls out Hermes Desktop's child-process scenario, but the simpler everyday case — the launcher that started the current invocation — appears to be unhandled.

Suggested fix

Exclude the immediate parent PID as well, and ideally any ancestor whose exe resolves to one of the shim paths:

exclude_pids: set[int] = {os.getpid()}
try:
import psutil
proc = psutil.Process()
while True:
parent = proc.parent()
if parent is None:
break
try:
parent_exe = str(Path(parent.exe()).resolve()).lower()
except (psutil.Error, OSError, ValueError):
break
if parent_exe not in shim_paths:
break
exclude_pids.add(parent.pid)
proc = parent
except Exception:
pass

Then check pid not in exclude_pids instead of pid == exclude_pid in the match loop.

Diagnostics already ruled out

While debugging this we also found D:\AI\hermes\gateway_state.json was stuck at gateway_state: "running" with updated_at: 2026-05-13 (a separate stale-lifecycle bug — gateway never wrote stopped after a
previous unclean shutdown). Removing/renaming that file did not affect the update gating, confirming the detector reads only live process state, not that JSON. Worth noting as a separate, smaller issue:
hermes gateway stop and/or update flows should normalize this state file.

Workaround

hermes update --force — works on every invocation in this environment. Documenting that it's the expected path on Windows until the parent-PID exclusion lands would help.

Steps to Reproduce

Run hermes update

Expected Behavior

Running hermes update on Windows when no other Hermes processes exist (no Desktop, no REPLs, no gateway, no orphaned children) should proceed with the update without requiring --force.

The console-script launcher process (Scripts\hermes.exe) that started the current update invocation is part of the same logical command and should not be detected as a "concurrent instance". The detector
should exclude both os.getpid() and any ancestor process whose executable resolves to one of the shim paths.

--force should remain available as an escape hatch for genuinely concurrent scenarios (Hermes Desktop child, second REPL), not as the default-required path for clean systems.

Actual Behavior

hermes update aborts with exit code 2 every time, reporting a "concurrent" hermes.exe PID. That PID is the launcher shim that spawned the current update Python process; it exits together with the
failed update, so by the time the user investigates, the PID is already gone. hermes update --force then succeeds without any actual concurrency conflict.

Affected Component

CLI (interactive chat)

Messaging Platform (if gateway-related)

No response

Debug Report

Security Advisories
  No active security advisories

Python Environment
  Python 3.11.15
  Virtual environment active

Required Packages
  OpenAI SDK
  Rich (terminal UI)
  python-dotenv
  PyYAML
  HTTPX
  Croniter (cron expressions) (optional)
  python-telegram-bot (optional, not installed)
  discord.py (optional, not installed)

Configuration Files
  D:\AI\hermes/.env file exists
  API key or custom endpoint configured
  D:\AI\hermes/config.yaml exists
  Config version up to date (v23)

Auth Providers
  Nous Portal auth (not logged in)
  OpenAI Codex auth (not logged in)
    No Codex credentials stored. Run `hermes auth` to authenticate.
    codex CLI not installed (optional only required to import tokens from an existing Codex CLI login)
  Google Gemini OAuth (not logged in)
  MiniMax OAuth (not logged in)
  xAI OAuth (not logged in)
    No xAI OAuth credentials stored. Select xAI Grok OAuth (SuperGrok Subscription) in `hermes model`.

Directory Structure
  D:\AI\hermes directory exists
  D:\AI\hermes/cron/ exists
  D:\AI\hermes/sessions/ exists
  D:\AI\hermes/logs/ exists
  D:\AI\hermes/skills/ exists
  D:\AI\hermes/memories/ exists
  D:\AI\hermes/SOUL.md exists (persona configured)
  D:\AI\hermes/memories/ directory exists
  MEMORY.md exists (549 chars)
  USER.md exists (669 chars)
  D:\AI\hermes/state.db exists (44 sessions)

External Tools
  git
  ripgrep (rg) (faster file search)
  docker not found (optional)
  Node.js
  agent-browser (Node.js) (browser automation)
  Playwright Chromium not installed (browser_* tools will be hidden from the agent)
    Install with: cd D:\AI\hermes\hermes-agent && npx playwright install chromium
  Browser tools (agent-browser) deps (no known vulnerabilities)

API Connectivity
  Running 27 connectivity checks in parallel                                                                      
  OpenRouter API
  Anthropic API (invalid API key)

Tool Availability
  clarify
  code_execution
  cronjob
  terminal
  delegation
  file
  memory
  moa
  session_search
  skills
  todo
  tts
  vision
  video
  kanban (runtime-gated; loaded only for dispatcher-spawned workers)
  browser (system dependency not met)
  browser-cdp (system dependency not met)
  computer_use (system dependency not met)
  discord (missing DISCORD_BOT_TOKEN)
  discord_admin (missing DISCORD_BOT_TOKEN)
  feishu_doc (system dependency not met)
  feishu_drive (system dependency not met)
  homeassistant (system dependency not met)
  image_gen (system dependency not met)
  messaging (system dependency not met)
  video_gen (system dependency not met)
  web (missing EXA_API_KEY, PARALLEL_API_KEY, TAVILY_API_KEY, FIRECRAWL_API_KEY, FIRECRAWL_API_URL, FIRECRAWL_GATEWAY_URL, TOOL_GATEWAY_DOMAIN, TOOL_GATEWAY_SCHEME, TOOL_GATEWAY_USER_TOKEN)
  x_search (missing XAI_API_KEY)
  hermes-yuanbao (system dependency not met)
  spotify (system dependency not met)

Skills Hub
  Skills Hub directory not initialized (run: hermes skills list)
  No GITHUB_TOKEN (60 req/hr rate limit set in D:\AI\hermes/.env for better rates)

Memory Provider
  Built-in memory active (no external provider configured this is fine)

  Found 1 issue(s) to address:

  1. Run 'hermes setup' to configure missing API keys for full tool access

  Tip: run 'hermes doctor --fix' to auto-fix what's possible.

Operating System

Windows 11

Python Version

3.11.15

Hermes Version

V0.14.0(2026.5.16)

Additional Logs / Traceback (optional)

Root Cause Analysis (optional)

No response

Proposed Fix (optional)

No response

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existscomp/cliCLI entry point, hermes_cli/, setup wizardtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions