Repository navigation
Hosted Go redirect leaves the superseded gopatch module's go.sum lines behind when a newer patch replaces an existing redirect, so go mod tidy is no longer a no-op #682
Description
[agent] Found by the scheduled Go modules bug-hunt routine (ledger #317).
Summary
When hosted mode re-redirects a Go module that already carries a Socket hosted replace, the old go.sum lines are left behind. This happens with a newer patch uuid for the same module@version, and when the same uuid is republished as vX.Y.Z-socketpatch.2. go.mod is updated correctly to the new patch.socket.dev/gopatch/<uuid> <version> target, and the new go.sum pair is added. But the previous target's two lines (<old module> <old version> h1: and .../go.mod h1:) stay in go.sum. The next go mod tidy deletes them, and go mod tidy -diff exits 1.
docs/ecosystems.md ("Go: directory replaces and go.sum") says "The rewriter removes the replaced version's original sum lines to keep the result stable under go mod tidy". The comment at redirect/mod.rs:6945 says the same ("keeps the first day-2 tidy a byte-level no-op"). That holds for the first redirect, but not for a refresh.
Impact
- Any CI that gates on tidy fails after a patch update:
go mod tidy -diff(go ≥1.23), orgo mod tidy && git diff --exit-code. The rewrite also leaves dead checksum lines for a module the build no longer references, and they pile up with every patch update. - The build itself is fine: it links the new patch, VEX attests the new uuid, and
rollbackrestores go.mod/go.sum byte for byte (it prunes everypatch.socket.dev/gopatch/line).
Repro (Linux, hermetic HTTP GOPROXY plus a local mock patch API, as in e2e_golang_hosted_build.rs)
Fixture: example.com/up@v1.0.0 (PRISTINE) and two published gopatch modules, patch.socket.dev/gopatch/1111…@v1.0.0-socketpatch.1 (PATCHED1) and patch.socket.dev/gopatch/2222…@v1.0.0-socketpatch.2 (PATCHED2). The mock serves view/<uuid> and POST /patches/package grants with a goproxy registryOverride for both.
# consumer: go.mod `require example.com/up v1.0.0`, tidy go.sum
socket-patch get 11111111-1111-4111-8111-111111111111 --mode hosted --yes --api-url $MOCK --org o --api-token x # exit 0
socket-patch get 22222222-2222-4222-8222-222222222222 --mode hosted --yes --api-url $MOCK --org o --api-token x # exit 0, redirected: 1, no warnings
grep replace go.mod
# replace example.com/up v1.0.0 => patch.socket.dev/gopatch/22222222-2222-4222-8222-222222222222 v1.0.0-socketpatch.2
cat go.sum
# patch.socket.dev/gopatch/11111111-… v1.0.0-socketpatch.1 h1:lWWp… <- stale
# patch.socket.dev/gopatch/11111111-… v1.0.0-socketpatch.1/go.mod h1:giFk… <- stale
# patch.socket.dev/gopatch/22222222-… v1.0.0-socketpatch.2 h1:FLV5…
# patch.socket.dev/gopatch/22222222-… v1.0.0-socketpatch.2/go.mod h1:giFk…
GOSUMDB=sum.invalid.example go run . # OUT: PATCHED2 (fine)
GOSUMDB=sum.invalid.example go mod tidy -diff # exit 1: removes the two 1111… linesSame-uuid variant: get 1111… (grant v1.0.0-socketpatch.1), then the service republishes the same uuid as v1.0.0-socketpatch.2 and get 1111… runs again. The socketpatch.1 lines stay, and tidy -diff exits 1 the same way.
Expected vs actual
- Expected (docs/ecosystems.md, Go notes): the hosted rewrite leaves go.sum in its tidy-stable state. When the rewriter replaces a prior Socket-owned hosted directive, it should also remove that directive's go.sum pair (the version-mismatch branch already does this with
remove_module_prefix_lines(stale_rhs)). - Actual: the old pair stays, and the first day-2
go mod tidyrewrites go.sum.
OS × version
| OS | go | variant | reproduces |
|---|---|---|---|
| Linux | 1.24.7 | new uuid | yes (3×) |
| Linux | 1.24.7 | same uuid, socketpatch.1 → .2 |
yes |
| Linux | 1.26.8 | new uuid | yes (tidy -diff exit 1) |
| Linux | 1.21.13 | new uuid | yes (go mod tidy shrinks go.sum from 4 lines to 2) |
| Linux | 1.24.7 | first redirect only (no prior) | no (tidy is a no-op) |
The bug is pure go.mod/go.sum text logic, so it doesn't depend on the OS. It isn't a regression: the 4.0.0 release (npm) behaves the same way. Tested on main 045d7ec.
Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs, rewrite_golang:
:6808:prior(the existing Socket hosted directive, with itsrhs_module/rhs_version) is captured, but on the normal refresh path it's only used for the ledgeroriginaltext.:6932:go_sum.upsert_module_lines(rhs_module, rhs_version, …)only replaces lines keyed on the newmodule version. Lines for the priorrhs_module/rhs_versionare never removed.:6859: the version-mismatch branch already prunesstale.rhs_modulelines. The refresh path needs the same treatment whenprior.owner == Hostedand(rhs_module, rhs_version)changed.
Not related to #631 (that issue is a refactor of the same go_sum_edit.rs file).
Activity
go: run 12 ledger (#682)
mikolalysenko commentedon Oct 3, 2026
[agent] Triaged: priority:p2 (Go modules). Not a duplicate of #549 (rollback after tidy) or #631 (refactor): this is the hosted refresh path in
rewrite_golangnot pruning the prior Socket target's go.sum pair. No open or merged PR addresses it yet.Generated by Claude Code
Drop a superseded hosted generation's wiring on re-pin and restore