The cleanest fix is to require the fixed version yourself with go get module@fixedversion. Minimal version selection then picks it for the whole build. Use exclude rarely, since it only blocks one version, and use replace only for a reviewed fork, because Go does not authenticate replaced modules.
Why upgrading works in Go
Go builds with the highest version any module in the graph requires. If a dependency asks for an old, vulnerable version of a library, you can add your own requirement on a newer one and the newer version wins. The Go supply chain article describes builds as locked by the main module's go.mod, so your requirement decides.
What exclude does
The Go reference says exclude prevents a module version from being loaded. It applies only in the main module's go.mod. Since Go 1.16, the excluded requirement is ignored, which can lead go get or go mod tidy to add a higher version. Before 1.16, the next higher non excluded version was loaded.
So exclude can work, but it is a blunt tool: it names what you do not want, not what you do. A direct requirement states the version you do want.
What replace does
Replace points a module at another path or version. The managing dependencies guide warns that Go tools do not authenticate external modules you replace. It is the right tool for a fork you maintain, not for routine fixes. See the replace directive.
Decision table
| Situation | Best option |
|---|---|
| A fixed release exists | go get module@fixed, then tidy |
| Parent module pins the old version and is maintained | Upgrade the parent, then drop your override |
| No fixed release, a patched fork exists | replace to a pinned tag of the fork, review it |
| A single bad version must never load | exclude, plus a direct requirement on a good one |
Steps
- Identify the path with
go mod why -mandgo mod graph. See finding who pulls a dependency. - Run
go get example.com/lib@v1.4.2, where v1.4.2 is the fixed release. - Run
go mod tidyand read the diff. - Run
go list -m example.com/libto confirm the selected version. - Test, rescan and note in the pull request which parent module caused the issue.
- When the parent updates, remove your direct requirement if the code does not import the library itself, and tidy again.
Try it yourself
Click through it at your own pace, or open it full screen. Look at how the fixed version is chosen and which files change.
Where Safeguard fits
Safeguard offers autonomous remediation with fix pull requests, off by default with every category on Manual. Dependency scanning is available through a free scan.
Quick check
Does exclude affect people who import my module?
No. Exclude only applies in the main module's go.mod and is ignored in other modules.
Why does go mod tidy sometimes add a higher version after exclude?
Since Go 1.16 an excluded requirement is ignored, so the go command may add a higher version.
Sources
Last reviewed: 19 October 2026.