hermes - ✅(Solved) Fix Windows: Terminal exits 126 with empty output on every command (Git Bash backend) [1 pull requests, 2 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#14638Fetched 2026-04-24 06:15:47
View on GitHub
Comments
2
Participants
1
Timeline
12
Reactions
0
Participants
Timeline (top)
labeled ×6commented ×2closed ×1cross-referenced ×1

Root Cause

Root Causes (3 independent bugs, same platform)

Fix Action

Fix

All three terminal bugs are small, local patches:

tools/environments/base.py — branch _drain on Windows and do blocking proc.stdout.read(4096) instead of select. Subprocess pipe handles aren't propagated to grandchildren on Windows (Py 3.7+), so EOF arrives promptly.

tools/environments/local.py

  • get_temp_dir(): on Windows, return tempfile.gettempdir().replace('\\', '/'). C:/Users/…/Temp is valid for both Python open() and Git Bash source.
  • Add _win_to_posix_path (C:\foo/c/foo) and _posix_to_win_path (/c/fooC:/foo).
  • Override LocalEnvironment._wrap_command to run cwd through _win_to_posix_path on Windows before building the script — fixes the builtin cd failure.
  • In _run_bash, feed _posix_to_win_path(self.cwd) to subprocess.Popen(cwd=…) so CreateProcess still gets a Windows path even if self.cwd was updated from pwd -P output.

tools/browser_tool.py — on Windows, detect .cmd/.bat shims and invoke via shell=True (or prepend ['cmd','/c']).

I've tested these patches locally against my install and am happy to send a PR if useful.

PR fix notes

PR #14644: fix(windows): native Git Bash terminal — exit 126 with empty output

Description (problem / solution / changelog)

Fixes #14638.

What this PR does

Makes the native-Windows / Git Bash terminal.backend: local path actually work. Currently every terminal() call returns exit_code: 126 with empty output; after this patch, echo hello returns hello, cwd persists across calls, and multi-line stdout is captured.

Root causes (three compounding bugs)

  1. select.select does not accept pipe fds on Windows. _drain in base.py hits OSError 10038 on the first iteration and exits without reading stdout → empty output, self.cwd never updated from the __HERMES_CWD__ marker.
  2. get_temp_dir() falls back to /tmp. Python on Windows resolves that to C:\tmp (doesn't exist), so _update_cwd's open() silently FileNotFoundErrors.
  3. builtin cd 'C:\Users\...' \|\| exit 126 — Git Bash's builtin cd does not accept single-quoted Windows backslash paths. Needs POSIX form (/c/Users/...). This is the direct source of the 126.

Fix

  • base.py: Windows branch in _drain uses blocking proc.stdout.read(4096) instead of select.select (Py 3.7+ subprocess on Windows doesn't propagate pipe handles to grandchildren, so EOF arrives promptly).
  • local.py: get_temp_dir() returns tempfile.gettempdir().replace('\', '/') on Windows — path valid for both Python and Git Bash.
  • local.py: new _win_to_posix_path / _posix_to_win_path helpers. LocalEnvironment._wrap_command is overridden to convert cwd before interpolation; _run_bash converts back for subprocess.Popen(cwd=).

All three are Windows-only branches; non-Windows code paths are untouched.

Verified locally

On Windows 11 + Git for Windows:

TEST 1 echo:  {\"output\": \"hello_from_fork\", \"exit_code\": 0, \"error\": null}
TEST 2 pwd:   {\"output\": \"/c/Users/WIN10/Projects/hermes-agent\", \"exit_code\": 0}
TEST 3 cd:    {\"output\": \"/tmp\", \"exit_code\": 0}
TEST 4 after: {\"output\": \"/tmp\", \"exit_code\": 0}   # cwd persisted

Known gaps (NOT in this PR)

This fixes the core terminal path only. Still broken on Windows/Git Bash:

  • pty=True — imports pty / termios which don't exist on Windows.
  • Process-tree kill — _kill_process on Windows only proc.terminate()s; backgrounded grandchildren can leak.
  • Browser tool WinError 193npx.cmd / agent-browser shim launched without shell=True.
  • Docker / SSH backend cwd translation on Windows hosts — untested here.

Happy to follow up with separate PRs for any of these.

Scope decision is yours

I realize this might be against current direction — the install docs say "Requires WSL2 on Windows" while the code's _find_bash() still searches C:\Program Files\Git\bin\bash.exe. If Git Bash support was deliberately deprecated, happy to flip this PR into the opposite change instead: delete the Windows branch in _find_bash(), fail loud at init with a clear "install WSL2" message, so users don't waste time debugging mysterious exit-126s.

Either direction is better than the current state (code half-supports Git Bash but silently fails). Let me know which you prefer and I'll adjust.


Why native Git Bash matters (user side, for context): WSL2 carries a ~1–2 GB RAM baseline, conflicts with VirtualBox/Android emulators via Hyper-V, and access to Windows-hosted repos incurs 9p filesystem perf costs. For users on constrained machines (which is the reporter's case), the native path is meaningfully cheaper — if it works.

Changed files

  • tools/environments/base.py (modified, +21/-0)
  • tools/environments/local.py (modified, +70/-1)
RAW_BUFFERClick to expand / collapse

Environment

  • Windows 11, Git for Windows (C:\Program Files\Git\bin\bash.exe)
  • Hermes installed via the official install.sh path; terminal.backend: local
  • Python 3.11 (Windows MSC build inside the hermes venv)

Reproduce

  1. Install Git for Windows + Hermes on Windows (no WSL).
  2. hermes chat, then run any terminal call — e.g. echo hello.
  3. Result: {\"output\": \"\", \"exit_code\": 126} every time.

Browser tool also fails on Windows with WinError 193 (not a valid Win32 application) on every navigation.

Root Causes (3 independent bugs, same platform)

1. select.select on pipe fds is not supported on Windows. tools/environments/base.py::_drain calls select.select([proc.stdout.fileno()], …), which raises OSError 10038 on Windows pipes. The except (ValueError, OSError): break swallows it and the drain thread exits immediately → stdout is never read. All terminal() calls return empty output, and _extract_cwd_from_output never sees the __HERMES_CWD__ marker so self.cwd is never synced.

2. get_temp_dir() returns /tmp. LocalEnvironment.get_temp_dir falls back to /tmp. Python on Windows resolves that to C:\tmp (non-existent), so the snapshot/cwd files written by Git Bash at /tmp/hermes-* can never be read back by Python — every open(self._cwd_file) silently FileNotFoundErrors.

3. builtin cd rejects single-quoted Windows backslash paths → exit 126. _wrap_command emits builtin cd 'C:\Users\…' || exit 126. Git Bash's cd builtin does not accept that form; it needs POSIX (/c/Users/…). This is the exact source of the 126.

(Bonus) Browser: tools/browser_tool.py launches npx/agent-browser (which are .cmd shims on Windows) via subprocess.Popen without shell=True, producing WinError 193.

Fix

All three terminal bugs are small, local patches:

tools/environments/base.py — branch _drain on Windows and do blocking proc.stdout.read(4096) instead of select. Subprocess pipe handles aren't propagated to grandchildren on Windows (Py 3.7+), so EOF arrives promptly.

tools/environments/local.py

  • get_temp_dir(): on Windows, return tempfile.gettempdir().replace('\\', '/'). C:/Users/…/Temp is valid for both Python open() and Git Bash source.
  • Add _win_to_posix_path (C:\foo/c/foo) and _posix_to_win_path (/c/fooC:/foo).
  • Override LocalEnvironment._wrap_command to run cwd through _win_to_posix_path on Windows before building the script — fixes the builtin cd failure.
  • In _run_bash, feed _posix_to_win_path(self.cwd) to subprocess.Popen(cwd=…) so CreateProcess still gets a Windows path even if self.cwd was updated from pwd -P output.

tools/browser_tool.py — on Windows, detect .cmd/.bat shims and invoke via shell=True (or prepend ['cmd','/c']).

I've tested these patches locally against my install and am happy to send a PR if useful.

Note

The install docs say "Requires WSL2 on Windows", but the code path actually targets Git Bash. Clarifying this (or actually supporting WSL2) would help.

extent analysis

TL;DR

Apply patches to tools/environments/base.py, tools/environments/local.py, and tools/browser_tool.py to fix Windows compatibility issues with Hermes.

Guidance

  • Verify the fixes by running hermes chat and checking the output of terminal calls, ensuring that stdout is read correctly and exit_code is not 126.
  • Implement the proposed patches:
    • In tools/environments/base.py, branch _drain on Windows to use blocking proc.stdout.read(4096) instead of select.
    • In tools/environments/local.py, update get_temp_dir() to return a valid Windows temp directory, and add path conversion functions to handle Windows and POSIX paths.
    • In tools/browser_tool.py, detect .cmd/.bat shims and invoke via shell=True on Windows.
  • Test the patches thoroughly to ensure they resolve the issues on Windows without introducing new problems.

Example

# tools/environments/base.py
if sys.platform == 'win32':
    # Use blocking read on Windows
    chunk = proc.stdout.read(4096)
else:
    # Use select on non-Windows platforms
    rlist, _, _ = select.select([proc.stdout.fileno()], [], [], 0)
    if rlist:
        chunk = os.read(proc.stdout.fileno(), 4096)

Notes

The proposed patches target the specific issues described, but it's essential to test them thoroughly to ensure they don't introduce new problems. Additionally, clarifying the installation documentation to reflect the actual support for Git Bash on Windows would be beneficial.

Recommendation

Apply the proposed patches to fix the Windows compatibility issues with Hermes, as they address the root causes of the problems and have been tested locally.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix Windows: Terminal exits 126 with empty output on every command (Git Bash backend) [1 pull requests, 2 comments, 1 participants]