Skip to content

Vendored uv repair can't rebuild a missing wheel once uv sync has installed it, because it rebuilds from the patched installed copy and the hash never matches #381

Description

[agent] Found by the scheduled uv bug-hunt routine (ledger #310).

Summary

On a vendored uv project, socket-patch repair restores a deleted .socket/vendor/pypi/<uuid>/<wheel> fine on a lock-only checkout: it fetches the pristine wheel from the ledger's registry fragment and reports rebuilt. On the normal developer checkout, where uv sync has already run, it fails. In that case the local build path (crates/socket-patch-core/src/vendor/pypi.rs:1824, "Local build from the installed dist") is taken first. The installed dist is the patched, uv-installed copy of the vendored wheel (uv's INSTALLER, direct_url.json, rewritten RECORD), so the rebuilt wheel never reproduces the sha256 uv.lock pins:

vendor_artifact_rebuild_failed: the rebuilt wheel (.socket/vendor/pypi/<uuid>/six-1.16.0-py2.py3-none-any.whl, sha256 a1b9797e…) does not match the wheel the lockfile still pins (…, sha256 01663f71…); run `socket-patch vendor --revert` for pkg:pypi/six@1.16.0 and re-vendor to re-wire the lockfile

The rebuilt sha is different on every run (a1b9797e…, 794ad96b…, fa13f665…, a2900bcf…, 071be102…), so retrying never helps. The run also removes the package's committed socket-patch.vendor.json sidecar (the documented "nothing kept" path). uv sync --locked then fails with failed to open file …six-1.16.0-py2.py3-none-any.whl.

Impact

The README describes repair as the command that "rebuilds missing/corrupt vendored artifacts". Here it only works if the user first deletes their virtualenv, which nothing tells them to do. The error points them to vendor --revert + re-vendor, which rewrites the lock unnecessarily. The case is common: any checkout where the wheel went missing (bad merge, LFS or .gitignore mishap) after uv sync.

Repro (Linux, uv 0.12.21)

Local mock patch API serving a patched six-1.16.0 wheel, as in the uv VEX e2e harness.

SP="socket-patch --api-url http://127.0.0.1:18080 --api-token t --org test-org"
mkdir proj && cd proj
printf '[project]\nname = "uvp"\nversion = "0.1.0"\nrequires-python = ">=3.9"\ndependencies = ["six==1.16.0"]\n' > pyproject.toml
printf '.venv\n' > .gitignore
uv lock && uv sync
$SP scan --mode vendored --json --yes        # applied: 1
git init -q && git add -A && git commit -qm vendored
cd .. && git clone -q proj clone && cd clone
uv sync --locked                             # installs the patched six.py ✔
rm .socket/vendor/pypi/*/six-1.16.0-py2.py3-none-any.whl
$SP repair --json                            # exit 1, failed vendor_artifact_rebuild_failed
uv sync --locked                             # fails: wheel file missing
# Control: the same steps WITHOUT the `uv sync --locked` in the clone -> repair "rebuilt", exit 0, --locked installs the patch.

Expected vs actual

  • Expected: repair rebuilds the committed wheel byte-for-byte, as it already does on a lock-only checkout. The ledger's wiring[].original fragment names the pristine PyPI wheel and its hash, so a verifiable pristine source exists. An installed copy that is itself the vendored (patched) wheel is not a pristine source and shouldn't be preferred over it.
  • Actual: vendor_artifact_rebuild_failed on every run, a non-deterministic rebuilt hash, and the vendor sidecar deleted.

OS × uv matrix (main f6b7fb9)

OS uv 0.2.37, venv present uv 0.12.21, venv present uv 0.2.37, lock-only (control) uv 0.12.21, lock-only (control)
Linux pass fail (3/3 runs) pass pass
macOS (arm64) pass fail pass pass
Windows fail fail fail¹ pass

¹ Windows + uv 0.2.37 fails even lock-only. The rebuilt wheel (01663f71…) matches what Linux vendoring produces, but not the wheel Windows vendoring committed. That suggests the original scan --mode vendored on that cell was also built from the installed dist, and so isn't reproducible from the pristine wheel. It's likely the same root cause, but I haven't isolated it.

First bad

Not bisected. The published 4.0.0 predates the current uv vendoring backend (#238 / #239).

Suspect code

Probe run

https://github.com/SocketDev/socket-patch/actions/runs/36776160780 (ubuntu / macos / windows × uv 0.2.37 and 0.12.21, lockOnly and withPatchedVenv cases)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions