Skip to content

venv on Windows preserves the \\?\ extended-length path prefix in sys.prefix on 3.14, unlike 3.10 - breaks tools that join sysconfig paths with relative (..) components #157917

Description

@AlReiter

Bug report

Bug description:

Repro

python -m venv "\\?\C:\path\to\venv" --system-site-packages --without-pip
"\?\C:\path\to\venv\Scripts\python.exe" -c "import sys; print(sys.prefix)"
  • Python 3.10.0: prints C:\path\to\venv
  • Python 3.14.0: prints \\?\C:\path\to\venv

Real-world consequence: installing any package with a scripts= file that has a shebang fails on 3.14, even on a fresh install. Minimal setup.py:

from setuptools import setup
setup(name="testpkg", version="1.0.0", py_modules=["testpkg"], scripts=["bottle.py"])

bottle.py:

#!/usr/bin/env python
print("hi")

pip install of the built wheel into the \\?\-prefixed venv above fails with:

ERROR: Could not install packages due to an OSError: [Errno 22] Invalid argument:
'\\?\C:\path\to\venv\Lib\site-packages\../../Scripts\bottle.py'

(Without the shebang line, the same package installs fine — the shebang is what makes pip rewrite the file and recompute its hash, which is what hits the broken path.)

(pip joins lib_dir with a RECORD-relative path like ../../Scripts/bottle.py via plain os.path.join — harmless on a normal path, but Windows does not resolve ..// for \\?\ paths, so open() rejects it. Reproduced identically with pip 24.3.1 and pip 26.2.1 — not pip-version-dependent.)

Root cause

  • 3.10 (PC/getpathp.c): the executable path used to derive sys.prefix always comes from GetModuleFileNameW(NULL, ...) — a WinAPI call that reports the OS's own canonical module path and never includes \\?\, regardless of how the process was invoked.
  • 3.14 (Modules/getpath.py/getpath.c): executable is taken from config.get('executable') (populated from the literal argv[0] used to invoke the process) and only falls back to the GetModuleFileNameW-derived real_executable when that's empty. Since argv[0] was \\?\C:\...\python.exe, it's used verbatim, \\?\ and all.

Suggested fix

In Modules/getpath.py, prefer real_executable (or strip a leading \\?\ / \\?\UNC\) over the literal configured executable on Windows when computing venv_prefix/prefix, restoring 3.10's behavior of always resolving through the OS-reported canonical path rather than trusting the invocation string.

CPython versions tested on:

3.14

Operating systems tested on:

Windows

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixesOS-windowstopic-venvRelated to the venv moduletype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions