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
Versioned executables (e.g., python3.13.exe) missing on Windows #1079
Description:
Versioned executables (e.g., python3.13.exe) are not installed on Windows while python313.dll, python-3.13.2-amd64.exe, and pip3.13.exe are installed. However, this is not the case on Linux or macOS, where versioned executables (or symlinks) are always present. This is inconvenient when using multiple versions at once.
Action version: v5
Platform:
Ubuntu
macOS
Windows
Runner type:
Hosted
Self-hosted
Tools version:
I tested 3.9 and 3.13.
Repro steps:
- name: Set up Pythonuses: actions/setup-python@v5with:
python-version: | 3.9 3.13
Expected behavior:
Versioned executables (or symlinks) are present on all platforms.
Actual behavior:
Versioned executables (or symlinks) are missing on Windows.
Hello @Rongronggg9👋,
Based on our investigation, for Windows, the Python executables, such as python-3.13.2.exe (for x86) and python-3.13.2-amd64.exe (for x64), are directly derived from the source code available on python.org and are architecture-specific.
For Cached Versions (e.g., 3.8.10): Python is pre-installed for both architectures (x86 and x64) on the runner for cached versions. Consequently, .exe files for both architectures are readily available in the tool cache. Please find this run for reference.
Non-Cached Versions (e.g., 3.8.1): Non-cached versions are downloaded and installed for a single architecture based on the default or specified value. When downloading a non-cached version, the action defaults to x64 if no architecture is specified.
The issue is never about patch-level versioned (e.g., 3.8.10) executables/symlinks, but minor-level versioned (e.g., 3.8) ones. The latter are always present on Linux or macOS. IMHO, it is hard to describe pinning to a patch-level versioned interpreter as a good practice.
You see, when I use setup-python with python-version: |\n 3.9\n 3.13, I need a reliable approach to launch both versions on all supported platforms. For 3.13, I can simply launch python as setup-python automatically sets it as the default interpreter in the current environment. The dilemma comes when I need to launch Python 3.9. I can launch python3.9 on Linux/macOS, but the same thing is missing on Windows. The situation makes the "Specifying multiple Python/PyPy versions" feature hardly useful in platform-matrixed CI workflows.
What's worse, when "Specifying multiple Python/PyPy versions", setup-python does not provide an approach to determine all (instead of only the last one, IIUC) the installed paths or patch-level versions. The only reliable information in my example is minor-level versions.
I am aware that this can be worked around by invoking setup-python in two different steps and capturing their output to get their patch-level versions or installed paths. But fundamentally speaking, this is just a workaround.
setup-python already empowers platform-matrixed CI workflows by setting the default interpreter as the last version specified to make it easy to write unified CI workflows. To make the "Specifying multiple Python/PyPy versions" feature useful, it'd be better if setup-python ensures the presence of versioned executables/symlinks according to the action input (i.e., given the input python-version: |\n 3.9\n 3.13, the presence of python3.9 and python3.13 should be ensured. This is irrelevant to the upstream behavior, but is meant to make setup-python's "Specifying multiple Python/PyPy versions" feature useful in platform-matrixed CI workflows with non-patch-level versions specified.
Hello @Rongronggg9👋,
Thank you so much for your detailed explanation and thoughtful feedback! We truly value your insights.
We’ll consider this as a feature request and will explore the possibility of implementing this enhancement in the future to ensure consistent availability of versioned executables across platforms. In the meantime, as you rightly suggested, invoking setup-python in two separate steps and capturing the output to retrieve the installed paths is a potential workaround.
Thank you once again for bringing this to our attention!
The dilemma comes when I need to launch Python 3.9. I can launch python3.9 on Linux/macOS, but the same thing is missing on Windows. The situation makes the "Specifying multiple Python/PyPy versions" feature hardly useful in platform-matrixed CI workflows.
I'm facing the same problem. I'd definitely consider this an issue, not a feature request.
@Rongronggg9 Do you have any hint how to best work around this issue?
The one you mentioned with separate setup-python steps is not actionable in my case as the python versions are dynamically controlled through an input...
Yet, this issue took an hour to figure out, another ~20 LOC + relying on implementation details, just because setup-python doesn't set up the versioned executables properly. This deserves being fixed.
To find Python 3.14, maturin first looks for python3.14.exe. The toolcache doesn't have one, so it asks the py launcher with py -3.14 instead. Normally that would return the preinstalled 3.14. But installing 3.14t replaces python.exe in its install folder with the free-threaded binary, and py -3.14 now returns that python.exe. So maturin gets the free-threaded interpreter for both 3.14 and 3.14t. It builds the cp314t wheel twice and the regular cp314 wheel never gets built. Nothing errors out, the wheel is just missing (log):
🐍 Found ... CPython 3.14t at C:\hostedtoolcache\windows\Python\3.14.8\x64-freethreaded\python.exe,
CPython 3.14t at C:\hostedtoolcache\windows\Python\3.14.8\x64-freethreaded\python3.14t.exe
📦 Built wheel for CPython 3.14t to dist\pyreqwest-0.13.0-cp314-cp314t-win_amd64.whl
📦 Built wheel for CPython 3.14t to dist\pyreqwest-0.13.0-cp314-cp314t-win_amd64.whl
As far as I can tell, maturin isn't doing anything wrong here. Looking for python3.14.exe and then falling back to py -3.14 is a reasonable way to find a specific Python version on Windows. It goes wrong because of how the toolcache is set up. Any other tool that looks up Python versions the same way would get the wrong interpreter too.
If the toolcache included versioned executables like python3.14.exe, as it already does on Linux and macOS, tools could find the right interpreter directly and none of this would happen. #1241 seems to be the same problem: there, installing 3.14t also replaced the existing 3.14.
Our workaround is to install 3.14t only after the regular wheels are built (working build):
Activity
v-priya-kinthali commentedon Apr 14, 2025
Hello @Rongronggg9👋,
Thank you for reporting this issue. We will investigate it and get back to you as soon as we have some feedback.
v-priya-kinthali commentedon Apr 22, 2025
Hello @Rongronggg9👋,
Based on our investigation, for Windows, the Python executables, such as
python-3.13.2.exe(for x86) andpython-3.13.2-amd64.exe(for x64), are directly derived from the source code available on python.org and are architecture-specific.For Cached Versions (e.g., 3.8.10): Python is pre-installed for both architectures (x86 and x64) on the runner for cached versions. Consequently,
.exefiles for both architectures are readily available in the tool cache. Please find this run for reference.Non-Cached Versions (e.g., 3.8.1): Non-cached versions are downloaded and installed for a single architecture based on the default or specified value. When downloading a non-cached version, the action defaults to x64 if no architecture is specified.
C:\hostedtoolcache\windows\Python\3.8.1\x64\python-3.8.1-amd64.exeC:\hostedtoolcache\windows\Python\3.8.1\x86\python-3.8.1.exeWe hope this clarifies. Please let us know in case of any further concerns. Thank you!😊
Rongronggg9 commentedon Apr 22, 2025
I am afraid that you misunderstood the issue.
The issue is never about patch-level versioned (e.g., 3.8.10) executables/symlinks, but minor-level versioned (e.g., 3.8) ones. The latter are always present on Linux or macOS. IMHO, it is hard to describe pinning to a patch-level versioned interpreter as a good practice.
You see, when I use
setup-pythonwithpython-version: |\n 3.9\n 3.13, I need a reliable approach to launch both versions on all supported platforms. For3.13, I can simply launchpythonassetup-pythonautomatically sets it as the default interpreter in the current environment. The dilemma comes when I need to launch Python 3.9. I can launchpython3.9on Linux/macOS, but the same thing is missing on Windows. The situation makes the "Specifying multiple Python/PyPy versions" feature hardly useful in platform-matrixed CI workflows.What's worse, when "Specifying multiple Python/PyPy versions",
setup-pythondoes not provide an approach to determine all (instead of only the last one, IIUC) the installed paths or patch-level versions. The only reliable information in my example is minor-level versions.I am aware that this can be worked around by invoking
setup-pythonin two different steps and capturing their output to get their patch-level versions or installed paths. But fundamentally speaking, this is just a workaround.setup-pythonalready empowers platform-matrixed CI workflows by setting the default interpreter as the last version specified to make it easy to write unified CI workflows. To make the "Specifying multiple Python/PyPy versions" feature useful, it'd be better ifsetup-pythonensures the presence of versioned executables/symlinks according to the action input (i.e., given the inputpython-version: |\n 3.9\n 3.13, the presence ofpython3.9andpython3.13should be ensured. This is irrelevant to the upstream behavior, but is meant to makesetup-python's "Specifying multiple Python/PyPy versions" feature useful in platform-matrixed CI workflows with non-patch-level versions specified.v-priya-kinthali commentedon May 6, 2025
Hello @Rongronggg9👋,
Thank you so much for your detailed explanation and thoughtful feedback! We truly value your insights.
We’ll consider this as a feature request and will explore the possibility of implementing this enhancement in the future to ensure consistent availability of versioned executables across platforms. In the meantime, as you rightly suggested, invoking
setup-pythonin two separate steps and capturing the output to retrieve the installed paths is a potential workaround.Thank you once again for bringing this to our attention!
mara004 commentedon Jul 2, 2026
I'm facing the same problem. I'd definitely consider this an issue, not a feature request.
mara004 commentedon Jul 2, 2026
@Rongronggg9 Do you have any hint how to best work around this issue?
The one you mentioned with separate
setup-pythonsteps is not actionable in my case as the python versions are dynamically controlled through an input...mara004 commentedon Jul 2, 2026
mara004 commentedon Jul 2, 2026
OK, workaround implemented:
https://github.com/pypdfium2-team/pypdfium2/blob/bcc5aabcc959a77e2994ad645b302a65a088968b/utils/multitest.py#L28-L45
Test runs (x64 and arm64):
https://github.com/pypdfium2-team/pypdfium2/actions/runs/28595575950/job/84789995019
https://github.com/pypdfium2-team/pypdfium2/actions/runs/28595812240/job/84790824567
Yet, this issue took an hour to figure out, another ~20 LOC + relying on implementation details, just because
setup-pythondoesn't set up the versioned executables properly. This deserves being fixed.MarkusSintonen commentedon Oct 1, 2026
We hit this when building wheels for both Python 3.14 and free-threaded 3.14t on Windows.
Our setup on
windows-2025:To find Python 3.14, maturin first looks for
python3.14.exe. The toolcache doesn't have one, so it asks thepylauncher withpy -3.14instead. Normally that would return the preinstalled 3.14. But installing 3.14t replacespython.exein its install folder with the free-threaded binary, andpy -3.14now returns thatpython.exe. So maturin gets the free-threaded interpreter for both3.14and3.14t. It builds thecp314twheel twice and the regularcp314wheel never gets built. Nothing errors out, the wheel is just missing (log):As far as I can tell, maturin isn't doing anything wrong here. Looking for
python3.14.exeand then falling back topy -3.14is a reasonable way to find a specific Python version on Windows. It goes wrong because of how the toolcache is set up. Any other tool that looks up Python versions the same way would get the wrong interpreter too.If the toolcache included versioned executables like
python3.14.exe, as it already does on Linux and macOS, tools could find the right interpreter directly and none of this would happen. #1241 seems to be the same problem: there, installing 3.14t also replaced the existing 3.14.Our workaround is to install 3.14t only after the regular wheels are built (working build):