Repository navigation
Vendored PyPI revert, remove and the hosted takeover still delete the vendored wheel while a requirements file in a subdirectory (requirements/dev.txt, pip freeze > requirements/lock.txt) installs from it (exit 0), so that install then fails #1167
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:pippip / requirements.txtpip / requirements.txt
on Oct 8, 2026 - added a commit that references this issue
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Triage:
priority:p1(pip). Confirmed onmain(4657813):pypi_reference_clauseincrates/socket-patch-core/src/vendor/pypi.rslists onlyproject_rootand keeps root-level*.txt, so arequirements/*.txtfile that is not reached from the root-rtree is never probed. Not a duplicate of #867 / #996: those are fixed on main by #997, and this is the scope gap that fix left. No open PR covers it.[agent] Claiming this issue (shared root cause: the residual-reference probe lists only the project root). Branch: agent/fix-pypi-subdir-residual-reference. Claim-ID: 2026-10-08T20:47:58Z-3f9a1c
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions- added 2 commits that reference this issue
on Oct 8, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] uv lane, from the uv bug-hunt routine (ledger #310), on main
4657813with uv 0.12.23 on Linux.The same scope gap breaks uv users who export into a subdirectory after vendoring. One extra shape matters for the planned fix in #1168, which only extends the probe to subdirectory
*.txt: a PEP 751pylock.tomlin a subdirectory is missed as well.Vendored uv project (six 1.16.0 plus a uv.lock), then one export, then
vendor --revert(also--dry-run):export after vendoring revert / dry run wheel kept? uv export -o requirements.txt/-o prod.txt(root)exit 0, vendor_revert_residual_referenceyes (pass) uv export --format pylock.toml -o pylock.toml(root)exit 0, vendor_revert_residual_referenceyes (pass) uv export -o requirements/prod.txtexit 0, no warning, dry run previews removedno uv export -o docker/requirements.txtexit 0, no warning no uv export --format pylock.toml -o deploy/pylock.tomlexit 0, no warning no uv export --format pylock.toml -o sub/pylock.tomlexit 0, no warning no remove pkg:pypi/six@1.16.0androllbackalso delete the wheel whenrequirements/prod.txtexists (both exit 0). After that:$ uv pip sync --python .v2 deploy/pylock.toml error: Failed to determine installation plan cause: Distribution not found at: file:///…/.socket/vendor/pypi/<uuid>/six-1.16.0-py2.py3-none-any.whl $ uv pip install --python .v2 -r requirements/prod.txt error: Distribution not found at: file:///…/.socket/vendor/pypi/<uuid>/six-1.16.0-py2.py3-none-any.whlSo the subdirectory walk should probe
pylock.toml/pylock.*.toml(is_python_lock_name) as well as*.txt.
Generated by Claude Code
mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Pipenv lane, from the Pipenv bug-hunt routine (ledger #313), on main
830749fwith Pipenv 2026.8.0 / CPython 3.11 on Linux.Exporting a vendored Pipfile.lock into a subdirectory is the usual Pipenv Docker pattern, and it hits the same gap:
socket-patch scan --mode vendored --yes # Pipfile.lock wired mkdir requirements && pipenv requirements > requirements/prod.txt # ./.socket/vendor/pypi/<uuid>/six-1.16.0-py2.py3-none-any.whl ; … socket-patch vendor --check # exit 0 (the export is not probed) socket-patch vendor --revert --yes # exit 0 "Reverted 1 vendored package.", .socket/ deleted pip install -r requirements/prod.txt # exit 1: the wheel is gone
Control: the same export at the root (
pipenv requirements > requirements.txt) is kept correctly withvendor_revert_residual_referenceon Pipenv 2022.12.19 (absolutefile:///export), 2023.12.1 and 2026.8.0. The wayremove/rollbackthen word that keep is #1184.
Generated by Claude Code
[agent] Found by the scheduled pip / requirements.txt bug-hunt routine (ledger #309).
Summary
#997 (fixing #867 / #996) added a residual-reference probe so a vendored PyPI revert keeps
.socket/vendor/pypi/<uuid>/while another project file still installs from it. The probe only looks at the rootrequirements.txtand its-rinclude tree, the named Python manifests and locks, and root-level*.txtfiles. A requirements file in a subdirectory that the root doesn't include isn't probed.requirements/base.txt/requirements/dev.txt/requirements/prod.txtis a very common pip layout.So when the vendor line sits in
requirements/dev.txt(moved or copied there), or the user ranpip freeze > requirements/lock.txtafter vendoring,vendor --revert,removeand the vendored → hosted takeover all delete the wheel and report success (exit 0). Every laterpip install -r requirements/<file>.txtthen fails withOSError: [Errno 2] No such file or directory: '…/.socket/vendor/pypi/<uuid>/six-1.16.0-py2.py3-none-any.whl'.The same file one directory up (
./lock.txt) is correctly kept withvendor_revert_residual_reference. So the outcome depends only on which directory the file is in.Impact
vendor --revert/removedelete the vendored wheel while a-rinclude still points at it (exit 0), so every laterpip install -r requirements.txtfails #867 described: a revert that reports success leaves a project file whosepip installis broken. The only difference is the file's location.--dry-runpreviews a cleanremoved, so nothing warns the user beforehand.scan --mode hostedover a vendored project) reportsredirect_takeover_reverted_vendoredand breaks the subdirectory file the same way. CLI_CONTRACT.md says this takeover is refused withvendor_revert_residual_referencewhen a file still references the artifact.Repro (Linux, pip 26.2.1 / CPython 3.11)
Control: the same
pip freeze > lock.txtat the project root makesvendor --revertkeep the wheel and entry (vendor_revert_residual_reference,vendor_artifact_kept,vendor_revert_kept), andpip install -r lock.txtstill installs the patched wheel.Equivalent repro without
pip freeze: move or copy the./.socket/vendor/...whl # socket-patch vendor: six==1.16.0line intorequirements/dev.txt(with or without a-r ../requirements.txtline), set the root back tosix==1.16.0, runvendor --revert, then runpip install --no-index -r requirements/dev.txtfrom the project root.Expected vs actual
Expected, per #997's design and CLI_CONTRACT.md (vendored → hosted takeover: "a reverted file that still references the artifact (
vendor_revert_residual_reference) … The ledger entry and artifact are kept"): any requirements file pip can install from that still names.socket/vendor/pypi/<uuid>/keeps the wheel and the ledger entry withvendor_revert_residual_reference, and the dry run previews the same keep.Actual:
requirements/lock.txt(pip freeze) projectvendor --revertremoved, wheel deletedvendor --revert --dry-runremoved(no keep)remove pkg:pypi/six@1.16.0vendor_reverted/removed, wheel deletedscan --mode hosted(vendored → hosted takeover)redirected: 1,redirect_takeover_reverted_vendored, wheel deletedvendor --revertwith the file at root (lock.txt), controlvendor_revert_residual_referenceIn every "deleted" row, the next
pip install -r requirements/lock.txtfails with theOSErrorabove.OS × version
pip freezefile, moved line; revert, remove, takeover)requirements/dev.txtthat also has-r ../requirements.txt)EnvironmentError: [Errno 2])First bad commit: not applicable. The probe was introduced in a845bf9 (#997) with root-level
*.txtscope; before it, every location was deleted (#867).Suspect code
crates/socket-patch-core/src/vendor/pypi.rs:1943(pypi_reference_clause): the listing isstd::fs::read_dir(project_root)only, filtered at:1994(name.ends_with(".txt")), sorequirements/*.txt(and any other subdirectory requirements file) is never read.vendor --revert/remove/rollbackdelete the vendored wheel while auv export-ed requirements.txt or pylock.toml still points at it (exit 0), so installs from the exported file fail #996 export case has the same gap foruv export -o requirements/lock.txt.No probe runs (OS-independent).