fix(powershell): probe python3 before selecting it in Get-Python3Command - #4151
Open
jawwad-ali wants to merge 1 commit into
Open
fix(powershell): probe python3 before selecting it in Get-Python3Command#4151jawwad-ali wants to merge 1 commit into
Get-Python3Command#4151jawwad-ali wants to merge 1 commit into
Conversation
Get-Python3Command's first branch returned @('python3') on mere Get-Command
presence, with NO execution probe -- while its own second and third branches
(python, py -3) DO probe with --version and match 'Python 3'. Its docstring
promises "a usable Python 3 executable".
On Windows, python3 almost always resolves to the Microsoft Store App
Execution Alias stub, which Get-Command finds but which fails at runtime:
found=True
source=C:\...\AppData\Local\Microsoft\WindowsApps\python3.exe
ver=[Python was not found; run without arguments to install from the
Microsoft Store...]
LASTEXITCODE=9009
match=False
This is the same hazard scripts/bash/common.sh documents by name (issue
github#3304) and defends against: its _python3_command probes all three
candidates, not just the last two.
Second half of the same root cause: the existing probes use
`& python --version 2>&1`. In Windows PowerShell, redirecting a native
command's stderr into the success stream wraps each line in an ErrorRecord,
so under the `$ErrorActionPreference = 'Stop'` every caller sets, the probe
raised a terminating NativeCommandError instead of simply failing the match.
Verified against upstream/main with shimmed interpreters on PATH:
python3 = dead stub, python = working -> RESULT=[python3] (dead)
python = dead stub, nothing else -> THREW: RemoteException
With the fix:
python3 = dead stub, python = working -> RESULT=[python]
python = dead stub, nothing else -> RESULT=[]
python3 + python dead, py -3 working -> RESULT=[py -3]
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Get-Python3Command's first branch returns@('python3')on mereGet-Commandpresence, with no execution probe — while its own second and third branches do probe:Its own docstring promises "a usable Python 3 executable".
On Windows,
python3almost always resolves to the Microsoft Store App Execution Alias stub, whichGet-Commandfinds but which fails at runtime:Note the existing probe already rejects it correctly — the first branch just never runs one.
Precedent in this repo
scripts/bash/common.shdocuments this exact hazard by name and defends against it:Its
_python3_commandprobes all three candidates. The PowerShell twin probes only the last two.Second half of the same root cause
The existing probes use
& python --version 2>&1. In Windows PowerShell, redirecting a native command's stderr into the success stream wraps each line in anErrorRecord— so under the$ErrorActionPreference = 'Stop'that every caller sets, the probe raises a terminatingNativeCommandErrorrather than simply failing the match. Reaching branch 2 therefore crashes outright whenpythonis also a Store alias (the Windows 11 default). One function, one fix.Reproduction — shimmed interpreters on PATH, against
upstream/mainCallers (
Resolve-TemplateContent→setup-plan.ps1,create-new-feature.ps1) then invoke the dead stub, whose stderr becomes a terminating error under'Stop', aborting the script instead of falling through to a working interpreter.With the fix:
Fix
Extract the probe into
Test-Python3Commandand apply it to all three branches. The probe saves and restores$ErrorActionPreferencearound the invocation so a candidate writing to stderr fails the match instead of throwing.Match semantics are unchanged — still
-match 'Python 3', exactly as branches 2 and 3 already did.Verification
common.ps1reverted toupstream/main→ 3 passed with the fix.PATH, so they do not depend on the runner actually having a Store alias. Gated onHAS_POWERSHELL.test_setup_tasks_ps_core_template_resolved— which is pre-existing on cleanmain, fails identically with and without this change, and has an unrelated cause (JSONDecodeError: Invalid control characterin emitted stdout). I am not claiming to fix it.common.ps1remains ASCII-only (verified byte-wise: 0 non-ASCII bytes), per this repo's.ps1encoding rule andtests/test_ps1_encoding.py, which passes.uvx ruff@0.15.0 check src tests→ cleanNo breaking change. A genuinely working
python3still passes the probe and is still selected first; only candidates that cannot actually run are now skipped — which is what the function already promised.Written with assistance from Claude Code. Bug found, reproduced, and verified by me on current
main.