Skip to content

Go apply and vendor break every build in projects with a committed vendor/ directory (modules.txt not synced), while apply --check and VEX report success #343

Description

[agent] Found by the scheduled Go modules bug-hunt routine (ledger #317).

Summary

In a Go project with a committed vendor/ directory (go mod vendor), both agent-mode apply and vendored-mode vendor add a go.mod replace and exit 0. Neither touches vendor/modules.txt. From then on, every go build / go run / go test fails:

go: inconsistent vendoring in …/c:
	example.com/upstream@v1.0.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt

With a vendor/ directory and go ≥ 1.14 in go.mod, go defaults to -mod=vendor and checks that modules.txt records every go.mod replace. apply --check still says Patch redirects are in sync (exit 0). vex attests not_affected. Nothing tells the user to re-run go mod vendor. rollback then breaks the build a second time, the other way round ("is marked as replaced in vendor/modules.txt, but not replaced in go.mod").

Impact

Committing vendor/ is common in large Go repos (Kubernetes-style monorepos, air-gapped CI). There, a successful socket-patch apply or vendor leaves the default build broken on every machine and in CI. That's "a rewrite that makes the next frozen install fail", and the CLI's own audit (apply --check) and VEX both call the state healthy. Running go mod vendor afterwards does produce a correct patched build (it copies the patched tree into vendor/), so the fix is to either do that sync (or its modules.txt equivalent) or refuse or warn up front.

Repro (hermetic file GOPROXY, the same fixture shape as tests/e2e_golang_build.rs)

export GOTOOLCHAIN=local GOSUMDB=off GOENV=off GOFLAGS= GOPROXY=file://$T/proxy GOMODCACHE=$T/modcache
# consumer requires example.com/upstream v1.0.0; go.mod says `go 1.16`
go mod vendor && go build ./...                    # ok
socket-patch apply --offline --ecosystems golang   # "1 of 1 targeted patch applied", exit 0
go build ./...                                      # exit 1: inconsistent vendoring (above)
socket-patch apply --check --ecosystems golang     # "Patch redirects are in sync (1 redirect checked)", exit 0
socket-patch vex --offline --output vex.json       # exit 0, not_affected
go mod vendor && go run .                          # OUT: PATCHED (the manual sync fixes it)
socket-patch rollback --offline --ecosystems golang  # exit 0
go build ./...                                      # exit 1: "is marked as replaced in vendor/modules.txt, but not replaced in go.mod"

socket-patch vendor --offline --ecosystems golang in place of apply behaves the same: exit 0, the replace => ./.socket/vendor/golang/<uuid>/… is written, the build fails with the same error, and vex attests not_affected.

Expected vs actual

  • Expected: docs/ecosystems.md ("Go: directory replaces and go.sum") describes the replace as the complete mechanism ("the committed patched tree itself is the protection … the wiring survives go mod tidy"). docs/design/golang-hosted.md says "go mod vendor vendors the PATCHED bytes … the vendored escape hatch composes". So a project that uses vendor/ should keep building after apply / vendor: either vendor/modules.txt (and vendor/<module>) get synced, or the command refuses or at least warns (go mod vendor required) and apply --check reports the inconsistency.
  • Actual: exit 0, a broken build, apply --check in sync, and VEX attests. vendor/modules.txt is never read or written anywhere in crates/ (README: "vendor/modules.txt is not read").

Matrix (probe run https://github.com/SocketDev/socket-patch/actions/runs/36746894687, plus local)

OS go agent apply vendored vendor
Linux 1.16.15 fail (build broken, exit 0) fail
Linux 1.21.13 fail fail
Linux 1.24.7 (local, 5 repros) fail fail
Linux 1.26.3 fail fail
macOS 1.24.13 / 1.26.3 fail fail
Windows 1.16.15 / 1.21.13 / 1.26.3 not reached: Go apply/vendor already fail on Windows with Access is denied. (os error 5), to be filed separately not reached

Release 4.0.0 behaves the same (checked locally). I couldn't compare 3.3.0 because it doesn't accept the hand-staged manifest. A go 1.13 go.mod with an explicit -mod=vendor fails the same way on go 1.24.

Suspect code

  • crates/socket-patch-core/src/patch/redirect/golang_local.rs:170 apply_go_redirect → go_mod_edit::ensure_replace_entry (crates/socket-patch-core/src/vendor/go_mod_edit.rs:175): only go.mod is edited.
  • crates/socket-patch-core/src/vendor/golang.rs:209 vendor_go_module: same.
  • golang_local::verify_go_redirect_state (apply --check) doesn't look at vendor/modules.txt.

Activity

  1. mikolalysenko commented on Sep 30, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triaged: priority:p2 (Go modules). Not a duplicate, and no open or merged PR fixes it. On main f6b7fb9, nothing under crates/ reads or writes vendor/modules.txt: apply_go_redirect and vendor_go_module both go only through go_mod_edit::ensure_replace_entry, and verify_go_redirect_state doesn't look at vendor/. This is a different cause from #344 (Go settings read only from the process env).


    Generated by Claude Code

  2. mikolalysenko commented on Oct 1, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Re-triage from the Go modules bug-hunt (ledger #317): this still reproduces on main 2463257 (v5 consolidation, #277), Linux, go 1.24.7. After go mod vendor, apply --offline exits 0 and go build fails with "is replaced in go.mod, but not marked as replaced in vendor/modules.txt". apply --check still reports "in sync".

    New shape with the same root cause: a workspace vendor directory (go work vendor, go 1.22+; go.work = go 1.22 / use .). apply exits 0, and go build ./... fails with the same inconsistent-vendoring error, this time suggesting go work vendor. apply --check still exits 0. So a fix that syncs vendor/modules.txt needs to handle the go work vendor layout as well as go mod vendor.


    Generated by Claude Code

  3. added a commit that references this issue on Oct 1, 2026
  4. mikolalysenko commented on Oct 1, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] New information: hosted mode is affected too. Reproduced 2× on main 61cfb9b (Linux, go 1.24.7).

    The fixture is the shape of e2e_golang_hosted_build.rs (get <uuid> --mode hosted against a local mock of view/<uuid> + /patches/package with a goproxy override). The consumer is go 1.21, with a committed vendor/ from go mod vendor, and go build ./... passes before the patch.

    socket-patch get $UUID --mode hosted --yes --json …  # exit 0, "redirected": 1, "rewrittenFiles": ["go.mod","go.sum"], "warnings": []
    go build ./...                                       # go: inconsistent vendoring …
                                                         #   example.com/upstream@v1.0.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt
                                                         # (same failure on a fresh day-2 machine)
    socket-patch vex … --product pkg:golang/example.com/consumer   # exit 0, "status": "not_affected" (redirected)
    

    So all three Go modes (agent, vendored, hosted) leave a committed-vendor/ project unbuildable with no warning, and VEX attests in all three.


    Generated by Claude Code

  5. added
    v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.
    compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.
    and removed on Oct 9, 2026
  6. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    v5 release blocker (P1). A normal Go project with committed vendor/ stops building after patching. Synchronize the required Go files, or give an actionable regeneration step before claiming the workflow is complete.

    This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.

  7. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming for v5 blocker burn-down (shared root cause: Go redirect wiring edits only the consumer go.mod replace; vendor/modules.txt and the consumer requirement graph/go.sum are never synced or checked). Branch: agent/v5-go-consumer-sync. Claim-ID: 2026-10-09T16:41:32Z-61a8f8

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

    agent:claimedagent:triagedbugSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentcompatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.pm:goGo modulespriority:p1v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions