Repository navigation
Hosted uv rollback and remove delete a user-authored override-dependencies = ["<pkg>==<ver>"] pin that hosted mode never added #411
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:uvuvuv
on Oct 1, 2026 mikolalysenko commented
on Oct 1, 2026 CollaboratorAuthorMore actions[agent] Triaged:
priority:p1(uv). Not a duplicate, and no open or merged PR covers it. The cause ispushed_overrideinupstream/uv.rs, which decides ownership by spelling alone. Without a ledger, a pre-existing<name>==<version>override can't be told apart from one the hosted run added, so the restore should keep the entry, or refuse, rather than delete it. That needs a design decision on what evidence of ownership to require (for example, the lock's[manifest] overridestogether with the hosted source), so it's not clustered with the pylock shape issues #407/#408.
Generated by Claude Code
mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Re-triage from the uv bug-hunt routine (ledger #310): this still reproduces on main
99f61d2. I ran the repro from the issue body against the local mock on Linux.uv rollbackremove pkg:pypi/six@1.16.00.5.31 fail fail 0.8.17 fail fail 0.12.23 fail fail Every cell: scan
redirected: 1, unwind exit 0 with warningsreinstall_requiredandupstream_uv_override_removed, and the user's own[tool.uv] override-dependencies = ["six==1.16.0"]is deleted (diffagainst the pre-scan pyproject shows only those three lines removed). The lock's[manifest] overridesis gone too. None of the uv unwind changes merged since045d7ec(#789, #822, #841, #818) touchpushed_override.
Generated by Claude Code
- added a commit that references this issue
on Oct 5, 2026 mikolalysenko commented
on Oct 8, 2026 CollaboratorAuthorMore actions[agent] Re-triage from the uv bug-hunt routine (ledger #310) on main
77f305d: this still reproduces. I also found a third path to the same data loss: the hosted → vendored takeover.Setup:
dependencies = ["python-dateutil==2.9.0.post0"]plus the user's own[tool.uv] override-dependencies = ["six==1.16.0"], thenuv lock. After that:scan --mode hosted: exit 0. The user's override becomes the hostedsix @ https://…entry.uv lock --checkpasses and six is patched.scan --mode vendored(the takeover): exit 0, eventsupstream_uv_override_removed→vendor_takeover_reverted_redirect→pypi_uv_override_requires_uv_0_5_6. The restore drops the override entirely, becausepushed_overridereads it as hosted-owned. The vendored backend then adds its own override and records "no override before vendoring" in the ledger.vendor --revert: exit 0success. It faithfully restores that pre-vendor state, so the user's[tool.uv]/override-dependencies = ["six==1.16.0"]lines are gone for good (diffagainst the original pyproject shows only those 3 lines removed). The--dry-runof step 2 previews a cleansuccessand doesn't mention the removal.
uv hosted takeover revert user override after revert 0.5.31 0 0 0 deleted 0.8.17 0 0 0 deleted 0.12.23 0 0 0 (×2) deleted This path is worse than the direct
rollback/removecase, because the deletion lands in the vendored ledger as the baseline. A laterremoveorrollbackof the vendored package can't bring the pin back either.uv lockkeeps six at 1.16.0 only because the lock still prefers it;uv lock --upgradewould now move it to 1.17.0. All runs were on Linux (it's pure text planning, with nothing OS-specific), with real uv and the local mock patch server.
Generated by Claude Code
- addedv5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actionsv5 release blocker (P1). A normal hosted scan/rollback must not delete a pre-existing uv override authored by the user.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Claiming for v5 blocker burn-down (shared root cause: hosted uv upstream restore decides override-dependencies ownership by spelling alone). Branch: agent/v5-uv-override-ownership. Claim-ID: 20261009T164135Z-ece7ea
- added a commit that references this issue
on Oct 9, 2026
[agent] Found by the scheduled uv bug-hunt routine (ledger #310).
Summary
On a uv project whose
pyproject.tomlalready pins a transitive dependency with[tool.uv] override-dependencies = ["six==1.16.0"], a hostedscanleaves that override alone and only adds the[tool.uv.sources]url.rollbackandremove pkg:pypi/six@1.16.0then delete the user's own override anyway. They also drop the now-empty[tool.uv]table and the lock's[manifest] overridesentry, and they warnupstream_uv_override_removed("removed thesix==1.16.0override-dependencies entry the hosted run adds"), which isn't true here.v5 hosted mode keeps no ledger, so the upstream restore guesses ownership:
pushed_overridetreats anyoverride-dependenciesentry spelled exactly<name>==<version>for a transitive dependency as the one the rewrite added (crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:1086). A user who pinned that exact version themselves can't be told apart, and loses the pin.Impact
This silently deletes user-authored resolver configuration. The lock still names 1.16.0 right after the rollback, so nothing fails at once. But the next
uv lock --upgrade(or any re-resolve) movessixto 1.17.0, which the user had explicitly overridden away from. The warning tells them hosted mode added the line, so they have no reason to put it back. An exact-version override of a transitive dep is the usual way to hold back a problematic transitive release, and a project with such a pin is a natural candidate forscan --mode hosted.Repro
Uses a local mock of the patch API serving a hosted
six-1.16.0wheel (the same mock as #379 / #381, now also returningintegrity.sha512), plus--patch-server-urlfor the mock origin. The PyPI JSON API must be reachable (in the sandbox I used a local forwarder viaSOCKET_PYPI_JSON_API; the probe runs hit pypi.org directly).Expected vs actual
override-dependenciesentry hosted mode added is removed (upstream_uv_override_removed)." An entry the user wrote before the scan should surviverollback/remove, as it does in vendored mode (whose ledger records the original). If ownership can't be decided without a ledger, the restore should keep the entry, or refuse with thegit checkoutremedy, rather than delete it.[tool.uv]and the lock's[manifest] overrides. Exit 0 /success, and a warning that blames hosted mode.OS × uv matrix (main
2463257)Each cell covers both
rollbackandremove. "fail" = user override deleted anduv lock --upgrade→ six 1.17.0. The no-socket-patch control keeps 1.16.0 in every cell.First bad
2463257(#277, the v5 upstream restore). Release 4.0.0 reverted from a recorded ledger fragment and has no upstream restore.Suspect code
crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:1086pushed_override: a spelling match on<name>==<version>, with no evidence the rewrite added it.crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:1103restore_metadata(removes the entry, then the empty tables) and:947/:996(drops the[manifest] overridesentry on the same guess).Probe run
https://github.com/SocketDev/socket-patch/actions/runs/36806727354 ("user override" groups in the
Run probestep)