Run go mod why -m example.com/module to see the shortest import path from your main module to a package in that module, and go mod graph to list which modules require which versions. Together they show who brought a vulnerable dependency in, so you know what to upgrade.
The two commands
According to the Go modules reference:
go mod whyshows a shortest path in the import graph from the main module to each listed package. Each target gets a stanza starting with a#comment line. An unused target shows "(main module does not need package ...)". The-mflag treats arguments as modules.go mod graphprints the module requirement graph, with replacements applied, one edge per line in the formpath@version dependency@version. The main module has no version suffix.
They answer different questions:
| Question | Command |
|---|---|
| Which of my packages imports this code? | go mod why |
| Which module versions require this version? | go mod graph |
| Is it even used in my build? | go mod why |
Steps to trace a finding
- Take the module and version from your scanner, for example a vulnerable
example.com/libat some version. - Run
go mod why -m example.com/lib. If it says the main module does not need the package, the module is only in the graph for version selection, which lowers urgency. - If there is a path, read it top to bottom. The first hop after your module is the dependency you control.
- Run
go mod graphand filter for the vulnerable module with grep to see every module that requires it, and at which version. - Choose the fix: upgrade the direct dependency that drags in the old version, or require the fixed version yourself with
go get example.com/lib@fixedversion. - Rerun both commands and your scanner to confirm the old version is gone.
Why the graph can mislead
Go uses minimal version selection, so the version in your build is the highest minimum any module in the graph asks for. An edge in the graph to an old version does not mean that version is built. Check go list -m example.com/lib for the version actually selected.
Also remember that a module can be in go.mod without contributing code. The Go team's supply chain article notes that modules that do not contribute code to a specific build have no security impact on it.
Try it yourself
Click through it at your own pace, or open it full screen. Look for how a transitive package is tied back to the direct dependency that brought it in.
Where Safeguard fits
Safeguard's SBOM and dependency scanning show direct and transitive packages, and reachability analysis helps rank which findings matter. A free scan is a quick way to see it on your repository.
Quick check
Does go mod graph show the version that is built?
No. It shows requirement edges. Use go list -m to see the selected version.
What does go mod why print for an unused module?
It prints that the main module does not need the package.
Sources
Last reviewed: 19 October 2026.