fix(windows): exclude the WSL launcher stub from bash candidates - #103502
Zhou1317fe5 wants to merge 1 commit into
Conversation
When the Git Bash probe fails under cold-start contention, _find_bash()
falls through to shutil.which("bash"), which on WSL co-install machines
resolves to the System32 launcher stub. That stub passes _bash_starts
(it is a working bash *inside WSL*), but /c/... and /d/... do not exist
there — the session snapshot then runs under the WSL filesystem view and
every command fails with ENOENT while the terminal tool burns its whole
executor timeout (NousResearch#103398).
Exclude the stub — resolved via %SystemRoot% (fallback %WINDIR%),
normcase-compared so non-C:\ Windows installs are covered too — and let
the existing structured "Git Bash not found" error surface instead.
When the Git Bash probe passes, behavior is unchanged.
Refs NousResearch#103398, NousResearch#74982. Complements NousResearch#83413 (probe stdin) and NousResearch#103402
(probe kill-tree).
Related: #41456 (rejects the same System32 WSL launcher when supplied via |
|
Independent field confirmation from a third host, plus the trigger I could isolate — this PR looks like the right fix. Host: Windows 11 (10.0.26200), git-installed Hermes v0.21.2 (2026.9.11, upstream Note this is not a missing-configuration case: Git Bash was correctly configured the whole time — Observed (every 34 occurrences in one day's Trigger: the 15 s probe timeout is a false negative when the MSYS image's first exec is slow. On this host (corporate endpoint-security agent + Defender) the first exec of So Verified locally with a one-line variant behaviourally identical to this PR (drop the def _is_wsl_bash(path: str) -> bool:
lowered = path.replace("/", "\\").lower()
return lowered.endswith("\\bash.exe") and ("\\system32\\" in lowered or "\\windowsapps\\" in lowered)
found = shutil.which("bash")
if found and not _is_wsl_bash(found) and found not in candidates:
candidates.append(found)
One note on the fallback after excluding the stub: on hosts with neither Happy to run a build with this PR applied on this exact host (Windows 11 + WSL + a probe that intermittently exceeds 15 s) if a live confirmation would help. |
When the Git Bash probe fails under cold-start contention,
_find_bash()falls through to
shutil.which("bash"), which on WSL co-install machinesresolves to the System32 launcher stub. That stub passes
_bash_starts(it is a working bash inside WSL), but
/c/...and/d/...do not existthere — the session snapshot then runs under the WSL filesystem view and
every command fails with ENOENT while the terminal tool burns its whole
executor timeout (#103398). Live capture during a failing window:
System32�ash.exe+wsl.exe+wslhost.exespawned together, and theerror signature is byte-identical when running the same snapshot commands
under
C:\Windows\System32�ash.exe.What this PR does
Exclude the stub from
_windows_bash_candidates()'sshutil.which("bash")fallback — resolved via
%SystemRoot%(fallback%WINDIR%) so non-C:\Windows installs are covered,
normcaseon both sides — and let theexisting structured "Git Bash not found" error surface instead. When the
Git Bash probe passes, behavior is unchanged.
Notes
kill-tree): those fix the hang; this fixes the silent degradation when the
probe still fails.
terminaltool hangs for minutes on trivial commands — bash startup probe deadlocks, and the probe child survivessubprocess.run's kill #103398, Windows: bash capability probe can hang a turn indefinitely — timeout kills only the bin\bash.exe shim; WSL bash can then win shell selection #74982, [Bug]: _find_bash() resolves to WSL bash before checking system Git-for-Windows paths on Native Windows #47837 (the original WSL-ordering report — theknown-locations fix from fix(terminal): force Git for Windows bash + convert native CWD for bash cd #56384 remains intact).
while stub dropped / non-stub PATH bash kept.
Environment: Windows 10 19045 x64, Git for Windows 2.49.0, WSL Ubuntu-24.04
co-installed. Full ACP wire logs and process captures available.