Skip to content

fix(windows): respawn gateway on the venv interpreter when captured argv leads with the base interpreter - #122144

Open
fotedev wants to merge 1 commit into
NousResearch:mainfrom
fotedev:fix/106489-venv-interpreter-relaunch
Open

fotedev wants to merge 1 commit into
NousResearch:mainfrom
fotedev:fix/106489-venv-interpreter-relaunch

Conversation

@fotedev

@fotedev fotedev commented Sep 25, 2026

Copy link
Copy Markdown

Problem

On Windows with a uv-managed venv, venv\Scripts\python.exe is a trampoline: it re-execs the base CPython, so a running gateway shows argv[0] = ...\uv\python\cpython-3.11-...\python.exe, with the venv shim only as its parent. The updater's pause/relaunch machinery snapshots that live argv and replays it verbatim on respawn, but windowless_gateway_restart_spec() passes a console interpreter through unchanged and the respawn env overlay (HERMES_HOME / VIRTUAL_ENV / PYTHONPATH) never sets __PYVENV_LAUNCHER__.

The respawned base interpreter imports hermes_cli from PYTHONPATH but has no venv site-packages and dies at the first import:

  File "...\hermes_cli\main.py", line 671, in <module>
    from hermes_cli.config import get_hermes_home
  File "...\hermes_cli\config.py", line 34, in <module>
    import yaml
ModuleNotFoundError: No module named 'yaml'

The 30 s liveness poll then fails (Windows gateway restart could not be verified — no stable gateway process appeared after relaunch), the update exits 1, and the gateway stays down — the desktop app is left showing "Content unavailable" on 127.0.0.1:12509 until a manual hermes gateway restart.

Observed in the wild on v0.21.4 (2026-09-25): after a git fetch network timeout aborted the update, both the in-process resume and the atexit safety-net respawned the gateway with the base interpreter; logs/gateway-stdio.log captured exactly the traceback above, once per attempt.

Fix

  • _resolve_detached_python(): when the incoming interpreter is the base interpreter of the venv this process runs from — matched against pyvenv.cfg's home= (BOM-tolerant read, case-insensitive normcase compare) — rewrite it to the venv's console python.exe. Callers that already pass the venv python are unaffected (its parent directory never equals the pyvenv home=); unrelated interpreters are left untouched. As a side effect, VIRTUAL_ENV stops pointing at the uv install dir on this path.
  • windowless_gateway_restart_spec(): when the resolved respawn interpreter belongs to this checkout's venv, add __PYVENV_LAUNCHER__=<venv python.exe> to the env overlay — belt-and-braces per the issue's suggestion, so a base-interpreter argv still resolves venv site-packages even if the argv rewrite is ever bypassed.

Scope note: point 3 of #106489 (the atexit double-fire) is already resolved by #116804 — this PR is strictly points 1 + 2.

cc @licat2023 — the issue notes a local patch was ready; if yours is still in flight, happy to stand down or fold the approaches together.

Verification

  • New regression tests in tests/hermes_cli/test_gateway_windows.py:
    • captured argv leading with the uv base interpreter (both python.exe and pythonw.exe spellings) respawns on the venv launcher, with the correct VIRTUAL_ENV and __PYVENV_LAUNCHER__;
    • venv-python argv stays byte-identical but still gets the launcher binding;
    • a foreign interpreter is left untouched and not bound to the watcher's venv;
    • a system-python watcher (sys.prefix == sys.base_prefix) sets no binding;
    • direct helper contract: pyvenv.cfg home= match, mismatch, missing launcher, missing cfg.
  • pytest tests/hermes_cli/test_gateway_windows.py tests/hermes_cli/test_update_gateway_launcher_refresh.py tests/hermes_cli/test_windows_update_restart_reconciliation.py tests/hermes_cli/test_windows_gateway_cold_start_desktop_lifecycle.py -q → 43 passed, 1 pre-existing failure (test_exec_schtasks_round_trips_non_ascii_task_argument_live — live schtasks /Create is denied on the reporting host; it fails identically on a clean tree).
  • ruff check (pinned 0.15.10) clean; ruff format introduces no changes to the added lines (both files carry pre-existing format drift in untouched regions); scripts/check-windows-footguns.py clean on the changed files (the helper reads pyvenv.cfg with utf-8-sig per the BOM policy).

Fixes #106489

…rgv leads with the base interpreter

A uv venv's Scripts\python.exe is a trampoline: a RUNNING gateway shows
argv[0] = the base CPython, so the updater's captured-argv respawn replayed
the base interpreter with no venv binding and died at 'import yaml'
(NousResearch#106489). Map that interpreter back to the venv launcher via pyvenv.cfg
home= and set __PYVENV_LAUNCHER__ in the respawn overlay as belt-and-braces.

Fixes NousResearch#106489
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard platform/windows area/install-update Installer, updater, packaging, wheels, doctor sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows labels Sep 25, 2026
@alt-glitch alt-glitch added os/windows Native Windows behaviour or breakage: PowerShell install, Windows paths, cmd.exe, WSL-vs-native diff and removed platform/windows labels Oct 17, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/install-update Installer, updater, packaging, wheels, doctor comp/cli CLI entry point, hermes_cli/, setup wizard os/windows Native Windows behaviour or breakage: PowerShell install, Windows paths, cmd.exe, WSL-vs-native diff P2 Medium — degraded but workaround exists sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Windows update exits 1 - post-update gateway relaunch replays the uv venv's base interpreter (No module named yaml)

2 participants