Repository navigation
Pipenv base-interpreter remedy (#1450) prints pipenv requirements --categories "packages docs", which Pipenv 2022.12.x–2023.2.4 export as empty, so following it installs nothing (exit 0) #1507
Description
[agent] Found by the scheduled Pipenv bug-hunt routine (ledger #313).
Summary
The #1450 fix (#1455) gives a --site-packages Pipenv venv that imports a stale base-interpreter copy a new remedy:
pipenv requirements<category args> > pipenv-locked.txt && pipenv run pip install --no-deps --ignore-installed -r pipenv-locked.txt
It labels the remedy "(Pipenv 2022.12+; …)" whenever it prints --categories. When the package is pinned in more than one lock category, and at least one of them is a named category ([packages] + [docs], [dev-packages] + [docs], [docs] + [tests]), sync_args renders the categories as space-separated Pipfile names: --categories "packages docs" / --categories "dev-packages docs". Pipenv 2022.12.19 and 2023.2.4 requirements split --categories on commas only and look up each name as a raw lock key. So "packages docs" is one category, which the lock doesn't have, and the export is empty (just the -i line). pip install -r of that file installs nothing and exits 0. The user sees success, but the venv still imports the unpatched base copy, and the next scan prints the same warning and the same remedy.
It fails closed: hosted vex omits the package with not_applied, and the warning re-fires. The defect is that the printed remedy does nothing on Pipenv versions it says it supports.
Impact
Pipenv 2022.12.x–2023.2.4 projects using --site-packages / PIPENV_SITE_PACKAGES=1 (distro python3-* packages, Docker base images, ~/.local user site) whose patched package sits in two or more lock categories, one of them named. Hosted and vendored modes print the same command (install_over_command).
Repro (Linux, Debian python3.11 with python3-six 1.16.0 in /usr/lib/python3/dist-packages, Pipenv 2022.12.19)
export WORKON_HOME=$PWD/workon PIPENV_SITE_PACKAGES=1
mkdir proj && cd proj
cat > Pipfile <<'EOF'
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
idna = "==3.7"
six = "==1.16.0"
[docs]
six = "==1.16.0"
EOF
pipenv --python /usr/bin/python3.11 lock && pipenv sync && pipenv sync --categories docs
pipenv run python -c 'import six; print(six.__file__)' # /usr/lib/python3/dist-packages/six.py
socket-patch scan --mode hosted --yes # (or --mode vendored)
# Warning: ... belongs to the base interpreter ... Install the locked release over it ...:
# `pipenv requirements --categories "packages docs" > pipenv-locked.txt && pipenv run pip install --no-deps --ignore-installed -r pipenv-locked.txt` (Pipenv 2022.12+; ...)
pipenv requirements --categories "packages docs" > pipenv-locked.txt && pipenv run pip install --no-deps --ignore-installed -r pipenv-locked.txt
echo $? # 0
grep -vc '^-i' pipenv-locked.txt # 0: nothing exported
pipenv run python -c 'import six; print(six.__file__)' # still /usr/lib/python3/dist-packages/six.py (upstream)
socket-patch scan --mode hosted --yes # same warning, same remedyI used a local mock patch API that serves a patched six-1.16.0 wheel. The oracle is the first line of the imported six.py.
What each Pipenv release exports from the same lock (default: idna, six; develop: six; docs: six):
pipenv requirements --categories … |
2022.12.19 | 2023.2.4 | 2023.2.18 | 2023.12.1 | 2026.9.1 |
|---|---|---|---|---|---|
"packages docs" (printed) |
empty | empty | idna six | idna six | idna six |
"dev-packages docs" (printed) |
empty | empty | six | six | six |
"default,docs" |
idna six | idna six | idna six | idna six | idna six |
"develop,docs" |
six | six | six | six | six |
docs (single, printed for a docs-only pin) |
six | six | six | six | six |
Pipenv 2023.2.18 switched to re.split(r", *| ", categories) and maps Pipfile names to lock keys. Before that, the code was categories.split(",") plus lockfile.get(category).
Expected vs actual
- Expected: docs/testing/pipenv-compatibility.md ("Base-interpreter copies survive both remedies", Pipenv stale-install remedy can't replace a base-interpreter copy in a
--site-packagesvenv:pip uninstallrefuses it andpipenv synckeeps it, so following the warning leaves the package unpatched #1450) says the printed command "installs the locked release inside the venv … (Pipenv 2022.4+, with the same category arguments)", and the warning itself says 2022.12+ for--categories. Following it on 2022.12.x should install the patched release. - Actual: on Pipenv 2022.12.19 and 2023.2.4 the export is empty, pip exits 0, the venv keeps the upstream base copy, and the warning loops.
A spelling that works on every release from 2022.12.19 to 2026.9.1 (see the table) is the comma-joined lock keys, e.g. --categories "default,docs" / "develop,docs". The alternative is to state 2023.2.18+ for the multi-category form.
OS × version
| OS | Pipenv | mode | shape | remedy result | runs |
|---|---|---|---|---|---|
| Linux | 2022.12.19 (py3.11) | hosted | [packages] + [docs] |
empty export, unpatched | 2/2 |
| Linux | 2022.12.19 (py3.11) | hosted | [dev-packages] + [docs] |
empty export, unpatched | 1/1 |
| Linux | 2022.12.19 (py3.11) | vendored | [packages] + [docs] |
empty export, unpatched | 1/1 |
| Linux | 2023.2.4 (py3.11) | hosted + vendored | [packages] + [docs] |
empty export, unpatched | 2/2 |
| Linux | 2022.12.19 | hosted | [docs] only (--categories "docs"), [dev-packages] only (--dev) |
PATCHED (pass) | |
| Linux | 2026.9.1 | hosted | [dev-packages] + [docs] |
PATCHED (pass) | |
| Linux | 2023.2.18, 2023.12.1, 2026.9.1 | — | export only | correct (pass) | |
| macOS / Windows | any | untested (probe branches blocked) |
Pipenv side: the first good release is 2023.2.18. socket-patch side: not a regression; the remedy is new in c04a19d (#1455). The generic pipenv sync --categories "packages docs" remedy (#790) is unaffected, because sync on 2022.12.19 accepts it (verified 2026-10-05).
Suspect code
crates/socket-patch-core/src/vendor/pypi_pipenv.rs:745sync_args: renders Pipfile names joined by spaces. That's right forsync/install, butinstall_over_command(:873) reuses it forpipenv requirements, which before 2023.2.18 needs comma-joined lock keys.crates/socket-patch-core/src/vendor/pypi_pipenv.rs:877: the "(present in 2022.12)" version note.
Tested on main aa85c6c (5.0.1).
Activity
pipenv: 2026-10-13 21:35Z bug-hunt run (#1507, #1450 verified)
mikolalysenko commentedon Oct 13, 2026
[agent] Claiming this issue (shared root cause:
install_over_commandreusessync_args, which renders space-joined Pipfile names thatpipenv requirementsbefore 2023.2.18 can't parse). Branch: agent/fix-pipenv-requirements-categories. Claim-ID: 2026-10-13T22:21:16Z-48ce7fGenerated by Claude Code
mikolalysenko commentedon Oct 13, 2026
[agent] Draft PR: #1508
Generated by Claude Code
Fix empty Pipenv export in base-interpreter fix
mikolalysenko commentedon Oct 14, 2026
[agent] Re-verified fixed on main
4a29912(5.0.1 + #1508), Linux, Debian python3.11 withpython3-sixin/usr/lib/python3/dist-packages,PIPENV_SITE_PACKAGES=1, local mock patch API serving a patched six 1.16.0 wheel. I followed the printed remedy verbatim in each cell.[packages]+[docs]--categories "default,docs"not_affected[dev-packages]+[docs]--categories "develop,docs"not_affected[tests]+[docs]--categories "docs,tests"not_affected[packages]+[docs]--categories "default,docs"not_affected[dev-packages]+[docs]--categories "develop,docs"not_affectedBefore the fix, the same shapes on 2022.12.19 and 2023.2.4 exported 0 lines.
Generated by Claude Code