Skip to content

Windows: Terminal exits 126 with empty output on every command (Git Bash backend) #14638

@Prasanna28Devadiga

Description

@Prasanna28Devadiga

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsbackend/localLocal shell executioncomp/agentCore agent loop, run_agent.py, prompt buildertool/browserBrowser automation (CDP, Playwright)tool/terminalTerminal execution and process managementtype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions