cmd/govulncheck/govulnchecklib: wrap Go version mismatch error

Wrap the errors due to a possible Go version mismatch error between
govulncheck and PATH with a message that communicates this clearly to
the user at the top.

Updates #55045

Change-Id: I9866b6ecef1a4d9410e5950092b04d85d5b1f28b
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/436275
Reviewed-by: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/cmd/govulncheck/govulnchecklib/errors.go b/cmd/govulncheck/govulnchecklib/errors.go
index 758d63b..ef86320 100644
--- a/cmd/govulncheck/govulnchecklib/errors.go
+++ b/cmd/govulncheck/govulnchecklib/errors.go
@@ -7,6 +7,7 @@
 import (
 	"errors"
 	"os"
+	"strings"
 )
 
 const noGoModErrorMessage = `govulncheck: no go.mod file
@@ -34,3 +35,19 @@
 	// for some other reason.
 	return true
 }
+
+const goVersionMismatchErrorMessage = `govulncheck: Go version mismatch
+
+Loading packages failed, possibly due to a mismatch between the Go version
+used to build govulncheck and the Go version on PATH. Consider rebuilding
+govulncheck with the current Go version.`
+
+// isGoVersionMismatchError checks if err is due to mismatch between
+// the Go version used to build govulncheck and the one currently
+// on PATH.
+func isGoVersionMismatchError(err error) bool {
+	msg := err.Error()
+	// See golang.org/x/tools/go/packages/packages.go.
+	return strings.Contains(msg, "This application uses version go") &&
+		strings.Contains(msg, "It may fail to process source files")
+}
diff --git a/cmd/govulncheck/govulnchecklib/main.go b/cmd/govulncheck/govulnchecklib/main.go
index 67da64c..1af27b4 100644
--- a/cmd/govulncheck/govulnchecklib/main.go
+++ b/cmd/govulncheck/govulnchecklib/main.go
@@ -94,6 +94,8 @@
 				die(noGoModErrorMessage)
 			} else if !fileExists(filepath.Join(cfg.Dir, "go.sum")) {
 				die(noGoSumErrorMessage)
+			} else if isGoVersionMismatchError(err) {
+				die(fmt.Sprintf("%s\n\n%v", goVersionMismatchErrorMessage, err))
 			}
 			die("govulncheck: %v", err)
 		}
diff --git a/go.mod b/go.mod
index 66715f3..88a502a 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@
 	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
 	golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
 	golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
-	golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3
+	golang.org/x/tools v0.1.13-0.20220928184430-f80e98464e27
 	honnef.co/go/tools v0.2.2
 	mvdan.cc/unparam v0.0.0-20211214103731-d0ef000c54e5
 )
diff --git a/go.sum b/go.sum
index aa1f730..cc25437 100644
--- a/go.sum
+++ b/go.sum
@@ -55,8 +55,8 @@
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3 h1:aE4T3aJwdCNz+s35ScSQYUzeGu7BOLDHZ1bBHVurqqY=
-golang.org/x/tools v0.1.13-0.20220803210227-8b9a1fbdf5c3/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.1.13-0.20220928184430-f80e98464e27 h1:mOqz7ZhDqMSA3LafrO1Q+1yLQ/KCnCy2/5xiFQVkCWQ=
+golang.org/x/tools v0.1.13-0.20220928184430-f80e98464e27/go.mod h1:VsjNM1dMo+Ofkp5d7y7fOdQZD8MTXSQ4w3EPk65AvKU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=