Skip to content

fix(update): never point uv at a nonexistent venv on out-of-tree installs - #116300

Closed
rocks737 wants to merge 1 commit into
NousResearch:mainfrom
rocks737:fix/update-out-of-tree-venv
Closed

rocks737 wants to merge 1 commit into
NousResearch:mainfrom
rocks737:fix/update-out-of-tree-venv

Conversation

@rocks737

Copy link
Copy Markdown

What does this PR do?

Fixes the hermes update failure reported in #116148: on installs whose interpreter lives outside the checkout ($HERMES_HOME\venvs\hermes — the layout the shipped Windows gateway launchers Hermes_Gateway.cmd/.ps1 themselves pin), the updater fabricated a VIRTUAL_ENV pointing at PROJECT_ROOT/venv, which does not exist there. uv then aborts every command with Failed to inspect Python interpreter from active virtual environment before doing any work.

Mechanism (why the update still reported success): the main dependency install self-heals — the #71510/#83335 guard drops a nonexistent VIRTUAL_ENV and pins sys.executable. But two unguarded consumers of _pip_install_prefix's env keep the fabricated path:

  • _upgrade_pip_before_lazy_refresh → the first uv interpreter error in the report
  • _restore_active_tool_dependencies → _resolve_install_target_python resolves no target from a nonexistent venv, the import probe never runs, every tools dep is classified missing, and the uv pip install fails → the second interpreter error + faster_whisper failed to restore

So hermes tools dependencies stay frozen at their install-time versions indefinitely, with only a one-line ⚠.

The fix

Stop fabricating; resolve. New canonical helper running_venv_root() in hermes_constants.py (pyvenv.cfg-verified — a bare /usr/bin/python must not read as a venv root). New shared resolver _resolved_install_venv_dir() in update_cmd.py:

  1. the checkout's in-tree venv/.venv when one exists (unchanged behavior)
  2. else the running interpreter's own venv root — the env the updater actually runs from on out-of-tree installs
  3. else leave VIRTUAL_ENV unset; uv/pip resolve from sys.executable (the proven fix(cli): target the managed install root in the ZIP update path #71510 pin path)

Both the git-pull path (_pip_install_prefix) and the ZIP fallback path (update_cmd_zip.py) now share the resolver so they cannot drift. The repair path's uv venv <dir> creation target is untouched — it creates the path it names, a different case.

Two sibling fabrication sites in cold-recovery paths (_install_repair.py, _early_recovery.py) are intentionally left: they run from a base interpreter repairing a broken in-tree install, a context where out-of-tree installs don't land, and the report shows neither fired (exactly two uv errors, both from the update flow).

Verification

  • New regression suite tests/hermes_cli/test_update_out_of_tree_venv.py (7 tests): real-venv detection, system-interpreter rejection, resolver precedence, env pinning, unset-when-unresolvable
  • Updated test_lazy_refresh_venv_repair.py contract assertion (it asserted the old fabricated-path behavior)
  • Full sweep: test_cmd_update.py, test_update_handoff_desktop_rebuild.py, test_update_concurrent_quarantine.py, test_update_sqlite_remediation.py, test_lazy_refresh_venv_repair.py + new suite → 105 passed
  • ruff clean on all touched files

Fixes #116148

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)

Checklist

  • Tests covering the fix are included and pass
  • No breaking changes; behavior for in-tree installs is identical

…alls

_pip_install_prefix (and the ZIP fallback) fabricated PROJECT_ROOT/venv
whenever the checkout had no in-tree venv. On out-of-tree installs — the
interpreter under $HERMES_HOME\venvs\hermes, the exact layout the shipped
Windows gateway launchers pin themselves — that path does not exist, and
uv aborts every command with 'Failed to inspect Python interpreter from
active virtual environment' before doing any work. The main dependency
install self-heals via the sys.executable pin (NousResearch#71510/NousResearch#83335), but the
unguarded consumers — pip upgrade before lazy refresh, and the
hermes tools dependency restore whose import probe resolves no target —
fail, so tool deps stay frozen while the update still reports success.

Resolve the install target instead of fabricating it: the checkout's
in-tree venv, else the running interpreter's own venv root
(running_venv_root, pyvenv.cfg-verified), else leave VIRTUAL_ENV unset
so uv/pip resolve from sys.executable. Shared resolver so the git-pull
and ZIP paths cannot drift; the repair path's uv venv creation target is
untouched (it creates the path it names).

Fixes NousResearch#116148
@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 Native Windows-specific behavior or breakage area/install-update Installer, updater, packaging, wheels, doctor sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows labels Sep 19, 2026
@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference; please use your judgment.

Overview

This PR stops two update paths (_pip_install_prefix and the post-zip reinstall) from pointing uv at a fabricated PROJECT_ROOT/venv on out-of-tree installs, via a shared _resolved_install_venv_dir resolver. The fixed paths and the new running_venv_root helper look correct, but the same fabricated-VIRTUAL_ENV idiom remains in at least eight sibling call sites, so the reported failure mode persists on those paths.

Findings

  1. hermes_cli/main_install_repair.py:450 (on main, untouched by this PR): the project_venv_dir(...) or <root> / "venv" fabrication this PR fixes in two places is still live there (non-blocking). (An earlier draft listed seven more sites; re-check showed update_cmd.py:690 is one of the two this PR fixes, update_cmd_deps.py:88 is a guarded interpreter probe that never sets VIRTUAL_ENV, and the rest do not hand a fabricated VIRTUAL_ENV to uv.) Each hands uv a VIRTUAL_ENV that does not exist on out-of-tree installs, reproducing the same Failed to inspect Python interpreter abort described in the PR. Suggested fix: route these sites through the new _resolved_install_venv_dir (or a shared equivalent) as a follow-up so the fix covers every update/repair entry point, not just the lazy-refresh and zip paths.

Minor: none.

teknium1 pushed a commit that referenced this pull request Sep 20, 2026
…<checkout>/venv

An install whose interpreter lives outside the checkout ($HERMES_HOME/venvs/<name> —
the layout the shipped Windows launchers assume) has neither venv/ nor .venv/ in-tree,
so project_venv_dir() returned None and every `project_venv_dir(root) or root / "venv"`
call site in the updater handed uv a VIRTUAL_ENV that does not exist (#116148): two uv
interpreter errors per update, the import probe skipped, every `hermes tools` dependency
reclassified as missing and reinstalled into a dead pointer, the staleness probe a no-op.

project_venv_dir() — the single choke point — now falls back to the venv of the
interpreter running this module, for the checkout it was loaded from only, so a foreign
root (test temp dir, another clone) still resolves to None. In-tree venv/.venv still wins.

Tests trimmed to two invariants in tests/test_hermes_constants.py.

Salvages #116293; supersedes #116300 (same fix at the two VIRTUAL_ENV export sites).
Co-authored-by: S <superb-cation@users.noreply.github.com>
@teknium1

Copy link
Copy Markdown
Collaborator

Thanks @rocks737 — this landed on main via #117029 (4f6c04c), superseded by the landed change (credited in the PR body): fix(update): out-of-tree venv installs refresh tool deps instead of pointing uv at \venv (#116148, salvage #116293)

Closing this PR as landed/superseded.

@teknium1 teknium1 closed this Sep 20, 2026
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 P2 Medium — degraded but workaround exists platform/windows Native Windows-specific behavior or breakage sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades 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]: hermes update never refreshes Python tool deps on out-of-tree venv installs — VIRTUAL_ENV points at a nonexistent <checkout>\venv

5 participants