Repository navigation
Hosted and vendored Poetry rewrites break poetry install on Poetry 1.4–2.2 when the patched dependency is declared with source = "pypi" ("Repository \"pypi\" does not exist."), with no warning #1282
Description
[agent] Found by the scheduled Poetry bug-hunt routine (ledger #311).
Summary
Poetry lets a dependency name the source it must come from: six = {version = "1.16.0", source = "pypi"}. Poetry's docs recommend this to pin a package to PyPI when a project also declares private or supplemental sources. Poetry records nothing extra in poetry.lock for a PyPI package, so socket-patch sees an ordinary PyPI entry. It rewrites it to [package.source] type = "url" (hosted) or type = "file" (vendored), and the scan exits 0 with no warning.
On Poetry 1.4.0 through 2.2.x, the next poetry install then fails: the installer matches the pyproject constraint source = "pypi" against a locked package whose source is now a URL or file. Poetry 1.6–2.2 print Repository "pypi" does not exist. Poetry 1.4 prints Because demo-app depends on six (1.16.0) which doesn't match any versions, version solving failed. Without the rewrite, the same project installs fine on every version, and Poetry 1.1, 1.2 and 2.3+ install the rewritten lock fine.
Impact
After scan --mode hosted or scan --mode vendored, every poetry install / poetry sync (CI, Docker builds, fresh clones) fails on the affected Poetry releases until the user reverts. socket-patch reports success (redirected: 1 / applied, exit 0) and emits no advisory. Nothing is silently left unpatched, because the install hard-fails, but the build breaks. vendor --revert / rollback restore a working install.
Repro (Linux, main e782c9a, local mock of the patch API serving a patched six-1.16.0 wheel)
mkdir demo && cd demo
cat > pyproject.toml <<'EOF'
[tool.poetry]
name = "demo-app"
version = "0.1.0"
description = ""
authors = ["x <x@example.com>"]
[tool.poetry.dependencies]
python = ">=3.8"
six = {version = "1.16.0", source = "pypi"}
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
EOF
export POETRY_VIRTUALENVS_IN_PROJECT=true
poetry lock --no-update # Poetry 1.8.5
poetry install --no-root # baseline: Installing six (1.16.0), exit 0
rm -rf .venv
socket-patch scan --mode vendored --yes # (or --mode hosted) exit 0, poetry.lock rewired, no warning
poetry install --no-root # exit 1: Repository "pypi" does not exist.
socket-patch vendor --revert --yes && poetry install --no-root # works againIt also reproduces with an extra declared source ([[tool.poetry.source]] name = "mirror", priority = "supplemental") beside source = "pypi" on 1.8.5. On 2.5.1 that shape installs fine.
Expected vs actual
- Expected: docs/testing/poetry-compatibility.md says both modes keep the package's dependencies, groups, markers and extras and that "no pyproject edit is required". It lists the lock shapes that are refused before any write (forked packages, a user-authored
[package.source]on another origin, …). A rewrite that makes the next install fail on a supported Poetry release should be refused before writing, like those shapes (or at least warned about, naming thesource = "pypi"constraint and the affected Poetry range). CLI_CONTRACT.md'sredirect_poetry_lock_unsupportedrow is the existing hosted refusal channel. The vendored twin would be apypi_poetry_*refusal. - Actual: both modes rewrite, report success, and leave a lock that Poetry 1.4–2.2 can't install.
OS × version
Each cell is a fresh project (poetry lock, then scan, then rm -rf .venv && poetry install --no-root). Baseline = the same project without socket-patch.
| OS | Poetry | baseline | hosted | vendored |
|---|---|---|---|---|
| Linux | 1.1.15 | pass | pass (patched) | pass (patched) |
| Linux | 1.2.2 | pass | pass | pass |
| Linux | 1.4.2 | pass | fail ("doesn't match any versions") | fail |
| Linux | 1.6.1 | pass | fail (Repository "pypi" does not exist.) |
fail |
| Linux | 1.7.1 | pass | fail | fail |
| Linux | 1.8.5 | pass | fail (×2, also with a supplemental source) | fail (×2) |
| Linux | 2.0.1 | pass | fail | fail |
| Linux | 2.1.1 | pass | fail | fail |
| Linux | 2.2.1 | pass | fail | fail |
| Linux | 2.3.3 | pass | pass | pass |
| Linux | 2.4.3 | pass | pass | pass |
| Linux | 2.5.1 | pass | pass (also with a supplemental source) | pass |
| macOS / Windows | — | not probed (probe branches are blocked for this routine). The failure is in Poetry's platform-independent installer/solver, so it's expected to match. |
The line endings of the lock don't matter here (the lock has no source data for six either way).
First bad version
Not a regression in socket-patch: the [package.source] rewrite shape has been the design since Poetry support landed (#241). The boundary is on Poetry's side (1.4.0 → 2.2.x).
Suspect code
socket-patch never reads the pyproject dependency's source key. The only source guard looks at the lock's own [package.source]:
crates/socket-patch-core/src/utils/poetry_lock.rs:531(shared rewriter: refuses only an existing locksource)crates/socket-patch-core/src/vendor/pypi_poetry.rs:234(vendored target guard, same)crates/socket-patch-core/src/patch/redirect/poetry.rs(hosted lane: thegenerated_by_version/pre_1_4_writeradvisories exist, but nothing for this constraint)
The lock's @generated by Poetry X.Y stamp (utils::poetry_lock::generated_by_version) is already available to gate on the affected range, though the installing Poetry may differ from the writer.
No probe runs: probe branches are blocked for this routine (see ledger #311).
Activity
mikolalysenko commentedon Oct 9, 2026
v5 triage: P2, not a release blocker. P2 compatibility follow-up for source="pypi" on Poetry 1.4-2.2. The report confirms current Poetry 2.3+ works and this predates v5; keep it out of the release gate while retaining the supported-version limitation.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commentedon Oct 12, 2026
[agent] Claiming this issue (shared root cause: the Poetry lock rewriters never read the pyproject dependency's
sourceconstraint). Branch: agent/fix-poetry-source-pypi-constraint. Claim-ID: 2026-10-12T03:21:01Z-d632c5Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
[agent] Draft PR: #1413
Generated by Claude Code
Refuse Poetry rewrites a source pin would break
Test and document Poetry source-pin refusal
Cover takeover and re-runs in Poetry source guard
Revert first in Poetry source-pin remedies
Scope the hosted rollback remedy to one package
Keep the private-index refusal for source pins
poetry: run 18 ledger (#1447 filed; #1282/#1023/#671 verified)