P2 Windows Reboot Leaves Stale gateway_state.json — Blocks Gateway Startup Indefinitely (#56396)

Executive Summary

On Windows 11, after an unplanned shutdown (or any reboot without a clean hermes stop), gateway_state.json retains the previous PID and gateway_state="running". On next boot, Hermes refuses to start: "Another gateway instance (PID xxxx) is already running" — even though no gateway process exists. Desktop enters a repair/retry loop. Root cause: Windows reuses PIDs after reboot, and the PID validation logic doesn't check process start time, causing a false positive. This is the 6th distinct Windows reliability bug we've tracked.

Root Cause Analysis (With Exact Code Paths)

The Failure Cascade on Windows

gateway_state.json After Reboot
1. gateway_state.json contains yesterday's PID and argv 2. Windows REUSES PIDs after reboot — the PID may now belong to an unrelated process 3. psutil.cmdline() raises AccessDenied or returns None for the recycled PID 4. The fallback path checks only the recorded argv (NOT start_time) 5. The stale record matches → FALSE POSITIVE: "gateway already running" 6. Startup blocked. Desktop retries endlessly.

The Buggy Code Path

In gateway/status.py, the chain: get_running_pid() → get_runtime_status_running_pid() → _record_matches_live_gateway_pid()

The critical gap: when psutil.cmdline() fails (AccessDenied on a recycled PID), the fallback path checks only the recorded argv — not the process start time. Since the recorded argv matches the gateway's expected argv pattern, the stale record is treated as a live gateway. On Linux/macOS, PIDs are not reused after reboot (pid_max starts fresh), so this bug is Windows-specific.

Reporter-Provided Fix

Proposed Fix in gateway/status.py
recorded_start = record.get("start_time") current_start = _get_process_start_time(pid) if recorded_start is not None and current_start is not None and recorded_start == current_start: return _record_looks_like_gateway(record) return False

The key insight: a false negative (starting a new gateway when the old one can't be verified) is safer than a false positive that permanently prevents startup. The start_time comparison definitively distinguishes "same process" from "different process with same PID."

Impact Assessment

DimensionSeverityDetail
Startup BlockingCRITICALHermes cannot start at all after an unplanned reboot. The user is locked out until they manually delete gateway_state.json — which most users won't know to do.
Recovery DifficultyHIGHDesktop enters a repair/retry loop with no clear error message. Users must find and delete a hidden state file manually.
Windows-SpecificHIGHThe PID-reuse behavior is Windows-specific. Linux/macOS don't reuse PIDs after reboot, so the bug only manifests on Windows — the platform with the most existing reliability issues.
Fix ComplexityLOWReporter provided exact diff with start_time comparison. One additional check in the PID validation path fixes the false positive.

Windows Reliability Bug History (6 Distinct Issues)

IssueSeverityDescription
#46260P2Installer fails at desktop stage (npm EBADENGINE)
#50897P2Desktop won't launch on Windows
#53069P2Missing simple-git module after upgrade
#54303P2Idle "Gt for Windows" process leak — continuous growth, high CPU
#54744P1Tool execution spawns 1,100+ Bash processes, freezes system
#56396P2Stale gateway_state.json blocks startup after reboot — PID reuse false positive

⚠️ Pattern: Six distinct Windows reliability failures spanning installation, launch, module resolution, idle behavior, tool execution, and now post-reboot recovery. Windows Desktop has a failure mode for every phase of the application lifecycle. The cumulative effect: a Windows user who installs Hermes, launches it, upgrades it, leaves it idle, runs a tool, and reboots — will encounter bugs at every single phase. No other platform has this density of independent failure modes.

Source Evidence

📋 https://hermes-agent.reviews/hermes-windows-stale-gateway-state-blocks-startup-56396.html
Tracked by hermes-agent.reviews — July 1, 2026