You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Windows: update/query fail with "can't open file" after PYTHONHASHSEED re-exec (uv tool install) #3779
On Windows, when graphify is installed with uv tool install graphifyy, every command that pins the hash seed fails immediately. That includes graphify update . and graphify query ...:
~\AppData\Roaming\uv\python\cpython-3.11-windows-x86_64-none\python.exe: can't open file '~\\.local\\bin\\graphify': [Errno 2] No such file or directory
Commands that don't re-exec, such as graphify --help, work fine.
Cause
The hash-seed pin added in #3641 re-execs like this (graphify/__main__.py, around L525):
On Windows, uv installs the console script as a launcher .exe. There, sys.argv[0] is ~\.local\bin\graphify (no extension, and not a Python file), so python <argv[0]> has nothing to run. The same will likely happen with pip/pipx console-script .exe launchers on Windows.
Suggested fix
Re-exec as a module so it doesn't depend on argv[0]:
Confirming this on a pip install, and reporting a second failure mode of the same re-exec that is worse than the one above because it produces no error at all.
Environment
graphifyy 0.9.66, installed with pip install --user (not uv)
Your prediction about pip launchers is correct. The report expects "the same failure with pip/pipx console-script .exe launchers on Windows." It does happen. I saw the identical message:
C:\Python313\python.exe: can't open file 'C:\Users<user>\AppData\Roaming\Python\Python313\Scripts\graphify':
[Errno 2] No such file or directory
Worth noting an aggravating detail specific to upgrades: 0.7.10 shipped an extensionless Scripts/graphify alongside the .exe, and 0.9.66 ships only the .exe. After upgrading, a shell that still resolves the old extensionless name hits this even when graphify.exe is present and working.
The same re-exec can fail completely silently, which is the more dangerous case. In other runs the process exited 0 with empty stdout and empty stderr, wrote no files, and produced no error line. From a script or CI wrapper that is indistinguishable from "ran fine, nothing to do." One variant exited 139 instead.
PYTHONFAULTHANDLER=1 is what surfaces the cause:
Windows fatal exception: access violation
Current thread 0x00003e54 (most recent call first):
File "", line 635 in execvpe
File "", line 621 in execvpe
File "...\graphify_main.py", line 525 in pin_hash_seed_if_needed
File "...\graphify_main.py", line 535 in main
File "...\graphify_main_.py", line 800 in
So on Windows the call does not always raise something catchable. Sometimes it takes the process down.
Because of that, the existing safety net cannot fire. The docstring says the function "degrades instead of raising if the re-exec itself fails, since an unusual host that disallows it should still be able to run graphify, just without this determinism guarantee." That intent is right, but:
An access violation is not an OSError. It terminates the interpreter, so except OSError: pass never runs and the graceful degradation does not happen.
Suggestion for PR #3780, beyond the argv fix. Switching to [sys.executable, "-m", "graphify", *sys.argv[1:]] addresses the argv[0] problem. Consider also skipping the re-exec entirely on Windows and setting the seed in-process, or treating the pin as best-effort by checking the child actually started. Silent-success is the failure mode most likely to be mistaken for correct behaviour, and it is the one users cannot see.
Verified workaround, for anyone hitting this before the fix lands. Set the variable yourself so the function returns early instead of re-execing. The value matches what it would have pinned, so determinism is preserved:
Affected commands are the members of _HASHSEED_PINNED_COMMANDS. I hit it on cluster-only; with PYTHONHASHSEED=0 set, extract, cluster-only and label all completed normally across a full rebuild.
Fixed in v0.9.67 via #3780 — the hash-seed pin re-execs via python -m graphify, fixing the Windows console-script launcher failure. Thanks @ayushcodes10.
Thanks for the quick fix. On 0.9.67 the launcher failure is gone: graphify --version works through the pip .exe launcher. The second failure mode from my comment above still happens, though.
Repro: python -m graphify label --help with PYTHONFAULTHANDLER=1, 10 runs each way. PYTHONHASHSEED unset: 139 0 0 0 139 139 0 0 0 0, 3 of 10 crash. PYTHONHASHSEED=0: 0 in all 10 runs. Every crash has the same stack: main.py:810 → main (:545) → _pin_hash_seed_if_needed (:531) → os.execvpe → Windows fatal exception: access violation.
So the -m graphify change fixed which file the new process opens, but the re-exec still goes through os.execvpe, and that call is what crashes. except OSError cannot catch it, because the process dies. A possible fix: on Windows, start the child with subprocess.run([sys.executable, "-m", "graphify", *sys.argv[1:]], env=env) and exit with its return code. Until then, PYTHONHASHSEED=0 skips the re-exec and worked in every run.
Activity
zandeto commentedon Sep 23, 2026
Confirming this on a pip install, and reporting a second failure mode of the same re-exec that is worse than the one above because it produces no error at all.
Environment
C:\Python313\python.exe: can't open file 'C:\Users<user>\AppData\Roaming\Python\Python313\Scripts\graphify':
[Errno 2] No such file or directory
Worth noting an aggravating detail specific to upgrades: 0.7.10 shipped an extensionless Scripts/graphify alongside the .exe, and 0.9.66 ships only the .exe. After upgrading, a shell that still resolves the old extensionless name hits this even when graphify.exe is present and working.
PYTHONFAULTHANDLER=1 is what surfaces the cause:
Windows fatal exception: access violation
Current thread 0x00003e54 (most recent call first):
File "", line 635 in execvpe
File "", line 621 in execvpe
File "...\graphify_main.py", line 525 in pin_hash_seed_if_needed
File "...\graphify_main.py", line 535 in main
File "...\graphify_main_.py", line 800 in
So on Windows the call does not always raise something catchable. Sometimes it takes the process down.
try:
os.execvpe(sys.executable, [sys.executable, *sys.argv], {**os.environ, "PYTHONHASHSEED": "0"})
except OSError:
pass
An access violation is not an OSError. It terminates the interpreter, so except OSError: pass never runs and the graceful degradation does not happen.
Suggestion for PR #3780, beyond the argv fix. Switching to [sys.executable, "-m", "graphify", *sys.argv[1:]] addresses the argv[0] problem. Consider also skipping the re-exec entirely on Windows and setting the seed in-process, or treating the pin as best-effort by checking the child actually started. Silent-success is the failure mode most likely to be mistaken for correct behaviour, and it is the one users cannot see.
Verified workaround, for anyone hitting this before the fix lands. Set the variable yourself so the function returns early instead of re-execing. The value matches what it would have pinned, so determinism is preserved:
PYTHONHASHSEED=0 python -m graphify cluster-only . --no-viz
Affected commands are the members of _HASHSEED_PINNED_COMMANDS. I hit it on cluster-only; with PYTHONHASHSEED=0 set, extract, cluster-only and label all completed normally across a full rebuild.
safishamsi commentedon Sep 23, 2026
Fixed in v0.9.67 via #3780 — the hash-seed pin re-execs via
python -m graphify, fixing the Windows console-script launcher failure. Thanks @ayushcodes10.zandeto commentedon Sep 25, 2026
Thanks for the quick fix. On 0.9.67 the launcher failure is gone: graphify --version works through the pip .exe launcher. The second failure mode from my comment above still happens, though.
Environment: graphifyy 0.9.67, pip install --user, Python 3.13.5, Windows 11 (10.0.26100), AMD64.
Repro: python -m graphify label --help with PYTHONFAULTHANDLER=1, 10 runs each way. PYTHONHASHSEED unset: 139 0 0 0 139 139 0 0 0 0, 3 of 10 crash. PYTHONHASHSEED=0: 0 in all 10 runs. Every crash has the same stack: main.py:810 → main (:545) → _pin_hash_seed_if_needed (:531) → os.execvpe → Windows fatal exception: access violation.
So the -m graphify change fixed which file the new process opens, but the re-exec still goes through os.execvpe, and that call is what crashes. except OSError cannot catch it, because the process dies. A possible fix: on Windows, start the child with subprocess.run([sys.executable, "-m", "graphify", *sys.argv[1:]], env=env) and exit with its return code. Until then, PYTHONHASHSEED=0 skips the re-exec and worked in every run.