[agent] Found by the scheduled Pipenv bug-hunt routine (ledger #313).
Summary
Vendored mode is meant for lock-only checkouts. The docs say "Lock-only checkout (nothing installed): … Discovered from the lock" (docs/testing/pipenv-compatibility.md, Formats table). But in a Pipenv project whose venv doesn't exist yet (a fresh CI checkout before pipenv install), the Python crawler still falls back to the global interpreter's site-packages. That's the same fallback as #504: get_site_packages_paths → is_python_project → get_global_python_site_packages(). So scan --mode vendored collects every patchable package from the OS Python (/usr/lib/python3/dist-packages on Debian/Ubuntu) as if it belonged to the project, then tries to vendor it into Pipfile.lock:
Error: Cannot vendor pkg:pypi/pyyaml@6.0.1: Pipfile.lock names pyyaml in neither default nor develop; run `pipenv lock` first
The run ends with status: partial_failure, exit 1, pypi_pipenv_lock_package_missing. The real lock packages (six, idna) do get vendored. The suggested remedy (pipenv lock) can't help, because pyyaml isn't a project dependency at all. --dry-run reports Would download and vendor 3 patches and doesn't flag the refusal, so the preview and the wet run disagree.
Hosted mode in the same state lists the system package as a project package with a patch and warns redirect_pipenv_skipped: Pipfile.lock has no entry for pyyaml (exit 0). scannedPackages is 149 (the whole system Python) instead of the lock's 2.
Impact
Repro (Linux, Debian/Ubuntu system Python with python3-yaml 6.0.1; mock patch API offering free patches for six 1.16.0, idna 3.7 and pyyaml 6.0.1)
mkdir app && cd app
cat > Pipfile <<'EOF'
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
six = "==1.16.0"
idna = "==3.7"
EOF
pipenv lock # Pipenv 2026.8.0; lock only
export WORKON_HOME=$PWD/../empty-workon # no Pipenv venv yet (fresh checkout)
mkdir -p "$WORKON_HOME"
socket-patch scan --mode vendored --yes --ecosystems pypi --json > out.json; echo "exit=$?"
# exit=1, status partial_failure
# vendor.events: pkg:pypi/pyyaml@6.0.1 failed pypi_pipenv_lock_package_missing
# six / idna applied
python3 -c "import yaml; print(yaml.__file__)" # /usr/lib/python3/dist-packages/yaml/__init__.py
Control: run pipenv sync first (the WORKON_HOME venv now exists). The same scan crawls only the venv (Found 4 packages), vendors six and idna, and exits 0.
Expected vs actual
- Expected: CLI_CONTRACT.md "cwd-only (single project)" says the crawler inspects only the project rooted at
--cwd, and global packages are the -g / --global-prefix surface. The Pipenv branch of find_local_venv_site_packages returns nothing on purpose when Pipenv has no venv yet. For vendored mode, the lock-only packages in Pipfile.lock are the whole candidate set. So a fresh checkout should vendor six and idna, exit 0, and never mention pyyaml.
- Actual: system-Python packages join the candidate set. Vendored exits 1 (
pypi_pipenv_lock_package_missing, with a misleading pipenv lock remedy). --dry-run promises they'll vendor. Hosted warns about them.
Cells (main 9c43dfc, CLI 4.0.0, Linux; lock written by Pipenv 2026.8.0, py3.11)
| Shape |
vendored |
hosted |
dry-run |
| Pipfile + lock, no Pipenv venv, system Python has a patchable pkg not in the lock |
❌ exit 1, partial_failure (2/2) |
⚠️ exit 0, redirect_pipenv_skipped for the system pkg, 149 scanned |
❌ "would vendor 3 patches" |
Same, after pipenv sync (WORKON venv present, control) |
✅ exit 0, 2 vendored |
✅ |
— |
The crawl doesn't depend on the Pipenv version (only the lock is Pipenv's, and every spec-6 lock behaves the same). macOS and Windows weren't probed: probe branches are blocked this run, see the ledger. Not bisected. The global fallback predates vendored Pipenv support, and #504 dates the Pipenv-branch half to #388 (ccd43f5).
Suspect code
crates/socket-patch-core/src/crawlers/python_crawler.rs:3047-3049: if is_python_project(&options.cwd) { return Ok(get_global_python_site_packages().await); } in non-global mode. Its doc comment justifies the fallback with "a fresh clone … would silently return zero packages", but lockfile-only packages are now merged from the lock, so that fallback is no longer needed for a Pipenv project.
crates/socket-patch-core/src/crawlers/python_crawler.rs:360-362: the Pipenv branch's empty result ("no venv yet, nothing to patch") can't be told apart from "nothing probed".
crates/socket-patch-core/src/vendor/pypi_pipenv.rs:172-178: the pypi_pipenv_lock_package_missing detail recommends pipenv lock even when the package isn't a project dependency.
Related: #504 (same fallback, agent mode writes the system Python). That triage noted #476 (Poetry) and #502 (PDM) end in the same fallback.
[agent] Found by the scheduled Pipenv bug-hunt routine (ledger #313).
Summary
Vendored mode is meant for lock-only checkouts. The docs say "Lock-only checkout (nothing installed): … Discovered from the lock" (
docs/testing/pipenv-compatibility.md, Formats table). But in a Pipenv project whose venv doesn't exist yet (a fresh CI checkout beforepipenv install), the Python crawler still falls back to the global interpreter's site-packages. That's the same fallback as #504:get_site_packages_paths→is_python_project→get_global_python_site_packages(). Soscan --mode vendoredcollects every patchable package from the OS Python (/usr/lib/python3/dist-packageson Debian/Ubuntu) as if it belonged to the project, then tries to vendor it intoPipfile.lock:The run ends with
status: partial_failure, exit 1,pypi_pipenv_lock_package_missing. The real lock packages (six, idna) do get vendored. The suggested remedy (pipenv lock) can't help, because pyyaml isn't a project dependency at all.--dry-runreportsWould download and vendor 3 patchesand doesn't flag the refusal, so the preview and the wet run disagree.Hosted mode in the same state lists the system package as a project package with a patch and warns
redirect_pipenv_skipped: Pipfile.lock has no entry for pyyaml(exit 0).scannedPackagesis 149 (the whole system Python) instead of the lock's 2.Impact
ubuntu-*runners and Debian/Ubuntu Docker images ship a system Python with packages like requests, urllib3, jinja2, cryptography and PyYAML. Whenever Socket has a patch for any of them, every vendored scan of a Pipenv project exits 1. That stays true while the project's own packages vendor fine, and the error tells the user to run a command that won't fix it.--max-new-patches) and the report include packages that aren't part of the project, so a rollout budget can be spent on the OS Python's packages.Pipfile.lock.Repro (Linux, Debian/Ubuntu system Python with
python3-yaml6.0.1; mock patch API offering free patches for six 1.16.0, idna 3.7 and pyyaml 6.0.1)Control: run
pipenv syncfirst (the WORKON_HOME venv now exists). The same scan crawls only the venv (Found 4 packages), vendors six and idna, and exits 0.Expected vs actual
--cwd, and global packages are the-g/--global-prefixsurface. The Pipenv branch offind_local_venv_site_packagesreturns nothing on purpose when Pipenv has no venv yet. For vendored mode, the lock-only packages inPipfile.lockare the whole candidate set. So a fresh checkout should vendor six and idna, exit 0, and never mention pyyaml.pypi_pipenv_lock_package_missing, with a misleadingpipenv lockremedy).--dry-runpromises they'll vendor. Hosted warns about them.Cells (main
9c43dfc, CLI 4.0.0, Linux; lock written by Pipenv 2026.8.0, py3.11)redirect_pipenv_skippedfor the system pkg, 149 scannedpipenv sync(WORKON venv present, control)The crawl doesn't depend on the Pipenv version (only the lock is Pipenv's, and every spec-6 lock behaves the same). macOS and Windows weren't probed: probe branches are blocked this run, see the ledger. Not bisected. The global fallback predates vendored Pipenv support, and #504 dates the Pipenv-branch half to #388 (
ccd43f5).Suspect code
crates/socket-patch-core/src/crawlers/python_crawler.rs:3047-3049:if is_python_project(&options.cwd) { return Ok(get_global_python_site_packages().await); }in non-global mode. Its doc comment justifies the fallback with "a fresh clone … would silently return zero packages", but lockfile-only packages are now merged from the lock, so that fallback is no longer needed for a Pipenv project.crates/socket-patch-core/src/crawlers/python_crawler.rs:360-362: the Pipenv branch's empty result ("no venv yet, nothing to patch") can't be told apart from "nothing probed".crates/socket-patch-core/src/vendor/pypi_pipenv.rs:172-178: thepypi_pipenv_lock_package_missingdetail recommendspipenv lockeven when the package isn't a project dependency.Related: #504 (same fallback, agent mode writes the system Python). That triage noted #476 (Poetry) and #502 (PDM) end in the same fallback.