Skip to content

fix(update): recover venv on Termux/proot when uv pip install fails#23579

Open
Endorpheen wants to merge 1 commit into
NousResearch:mainfrom
Endorpheen:fix-termux-proot-update-recovery
Open

fix(update): recover venv on Termux/proot when uv pip install fails#23579
Endorpheen wants to merge 1 commit into
NousResearch:mainfrom
Endorpheen:fix-termux-proot-update-recovery

Conversation

@Endorpheen

Copy link
Copy Markdown

What does this PR do?

Fixes hermes update failures inside Termux/proot-distro environments where uv pip install cannot reliably copy package files into site-packages/, leaving the virtual environment partially broken.

Related Issue

No existing issue found. Observed on Termux + proot-distro Ubuntu (aarch64).

Type of Change

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

Problem

On Termux/proot-distro, hermes update successfully pulls code via git but crashes during dependency installation:

Failed to install: google_api_core-2.30.3...
Caused by: failed to copy file from /root/.cache/uv/archive-v0/.../google/api_core/__init__.py
to .../venv/lib/python3.11/site-packages/google/api_core/__init__.py:
No such file or directory (os error 2)

Root causes:

  1. uv pip install on proot-distro fails with ENOENT/EPERM file-copy errors due to proot filesystem translation limitations
  2. Failed installs leave empty package directories and packages with .py files but missing __init__.py
  3. Subsequent uv runs see stale .dist-info metadata and skip reinstallation, believing packages are already installed
  4. _is_termux_env() only detected native Termux ($PREFIX), not proot-distro environments (Ubuntu kernel reports 6.17.0-PRoot-Distro)
  5. No fallback to regular pip when uv fails on Termux/proot

Affected packages included google_api_core, psutil, aiohttp, rich, anthropic, and ~200 others.

Changes Made

hermes_cli/main.py — 287 lines added, 6 changed

Termux/proot detection (_is_termux_env)

  • Extended to detect proot-distro via os.uname().release containing "PRoot" + presence of /data/data/com.termux, in addition to the existing $PREFIX check

Venv validation (_validate_and_fix_venv, new function)

Runs before every dependency install during update:

  1. Verifies venv Python binary exists and works; recreates venv if broken
  2. Cleans empty package directories left by failed installs
  3. Removes packages with .py files but missing __init__.py (hallmark of partial uv copies)
  4. Removes orphaned .dist-info metadata (package removed but metadata remains, causing uv/pip to skip reinstallation)
  5. Smoke-tests critical imports (rich, httpx, openai, anthropic, psutil) and triggers full reinstall if any are missing

uv-to-pip fallback

  • When uv pip install raises CalledProcessError on Termux/proot, falls back to python -m pip install -e .[termux-all]
  • On non-Termux environments, the original CalledProcessError propagates unchanged (no behavior change)

Safe venv recreation (_recreate_venv, new function)

  • Recreates venv from scratch using stdlib venv
  • User data (configs, state, memory, history) lives under $HERMES_HOME (typically ~/.hermes), not inside the venv, so this is safe

Helper functions

  • _is_empty_dir / _remove_empty_subdirs — directory cleanup
  • _find_broken_packages — detects packages with .py files but no __init__.py
  • _find_orphaned_dist_info — detects .dist-info without corresponding package directory
  • _has_missing_core_deps — quick import smoke-test for critical packages

How to Test

On Termux + proot-distro Ubuntu (aarch64):

cd /root/.hermes/hermes-agent
hermes update    # should complete without ENOENT errors
hermes doctor    # should pass all package checks
hermes --help    # should display help
hermes --version # should show version

On regular Linux/macOS (no regression):

hermes update    # should work as before, using uv

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass — not run: pytest is broken in this venv (same uv partial-copy issue affecting _pytest/__init__.py)
  • I've added tests for my changes — these functions are tightly coupled to venv/site-packages layout and proot-specific filesystem behavior; unit tests would require extensive mocking. Manual validation performed on real Termux/proot environment.
  • I've tested on my platform: Termux + proot-distro Ubuntu 25.10 (aarch64)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A (all new functions have docstrings)
  • I've updated cli-config.yaml.example if I added/changed config keys — N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — N/A (all changes gated behind _is_termux_env())
  • I've updated tool descriptions/schemas if I changed tool behavior — N/A

Notes / Limitations

  • The _is_termux_env() proot detection checks os.uname().release for the string "PRoot" and verifies /data/data/com.termux exists. This is specific to proot-distro but should cover all Termux-based proot environments.
  • The _has_missing_core_deps() probe list (rich, httpx, openai, anthropic, psutil) is a fixed set of critical packages. If the project's required dependencies change significantly, this list may need updating.
  • The uv-to-pip fallback only triggers on Termux/proot. On regular platforms, uv failures propagate as before.
  • ruff and pytest were not available in the test environment (broken by the same uv issue this PR fixes). Python compilation check passed.

@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 python:uv Pull requests that update python:uv code labels May 11, 2026
@Endorpheen Endorpheen marked this pull request as ready for review May 11, 2026 05:11
On Termux/proot-distro, `uv pip install` can fail with ENOENT/EPERM when
copying files into site-packages, leaving a broken venv with empty
directories and missing __init__.py files. Subsequent installs then fail
repeatedly because uv tries to write into the same broken paths.

Changes:
- Add proot-distro detection to _is_termux_startup_environment() via
  os.uname() release/version containing "PRoot" + /data/data/com.termux
- Add _validate_and_fix_venv() which runs before dependency installation:
  verifies venv Python works, cleans empty dirs, removes broken packages,
  removes orphaned .dist-info, recreates venv if needed
- Add helper functions: _is_empty_dir, _remove_empty_subdirs,
  _find_broken_packages, _find_orphaned_dist_info,
  _has_missing_core_deps, _recreate_venv
- Add uv→pip fallback: if uv fails on Termux/proot, catch the error
  and fall back to regular pip instead of crashing the whole update
- Use termux-all profile for pip fallback path on Termux/proot
- No behavior change on regular Linux/macOS/Windows

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Endorpheen Endorpheen force-pushed the fix-termux-proot-update-recovery branch from df15f33 to 7c6c07f Compare June 6, 2026 05:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists python:uv Pull requests that update python:uv code type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants