Description
Go version
that's a good question!
Output of go env
in your module/workspace:
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/dominikh/.cache/go-build'
GOENV='/home/dominikh/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/dominikh/prj/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/dominikh/prj'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/dominikh/prj/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.1.linux-amd64'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/dominikh/prj/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.1.linux-amd64/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.1'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/dominikh/bla/go.mod'
GOWORK=''
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build3151298505=/tmp/go-build -gno-record-gcc-switches'
What did you do?
As the author of Staticcheck, I tell my users that to support Go 1.22 code, they have to build Staticcheck with Go 1.22. To assure me that they did, they show me this:
$ go version
go version go1.22.1 linux/amd64
$ go install honnef.co/go/tools/cmd/staticcheck@latest
The problem is that the user's local toolchain is Go 1.21.8, but the module they're currently in is specifying go 1.22.1
in its go.mod. Running go version
downloads and runs the newer toolchain, as does go install .
, but go install honnef.co/[...]
does not.
This is problematic in a multitude of ways.
- I don't know of any straightforward way to get the local toolchain's version without having to change the current working directory
- Users wouldn't even know to use it if they aren't aware of this footgun
- This interaction is just a symptom; the actual problem is that users have no good intuition for which version of Go they're actually using. In fact, this behavior confused 3 of 3 experienced Go users that I showed it to, as well as a dozen users of mine who struggled to build Staticcheck with Go 1.22. Most of them misdiagnosed the problem as the build cache not being invalidated correctly, because they thought they were building Staticcheck with 1.22 when they were in fact using their older, local toolchain.
That go install
behaves this way is documented in go help install
as
If the arguments have version suffixes (like @latest or @v1.0.0), "go install"
builds packages in module-aware mode, ignoring the go.mod file in the current
directory or any parent directory, if there is one. This is useful for
installing executables without affecting the dependencies of the main module.
This, however, predates the automatic upgrades. In my experience, users who are aware of automatic upgrades think of it as "First, go
downloads the specified toolchain, then it runs the subcommand", which is true in most, but not all cases.
The issue I am filing is really a mix of two user reports, one from the perspective of a tool maintainer, and one from the perspective of a user. What they have in common is confusion over the effective Go version.
To avoid any confusion I've included a sample shell session demonstrating the current behavior.
chulak ~ ^$ go version
go version go1.21.8 linux/amd64
chulak ~ ^$ mkdir bla
chulak ~ ^$ cd bla
chulak ~/bla ^$ go mod init example.com
go: creating new go.mod: module example.com
chulak ~/bla ^$ go get go@1.22.1
go: updating go.mod requires go >= 1.22.1; switching to go1.22.1
go: upgraded go 1.21.8 => 1.22.1
chulak ~/bla ^$ go version
go version go1.22.1 linux/amd64
chulak ~/bla ^$ echo "package main\nfunc main(){}" >main.go
chulak ~/bla ^$ rm $GOPATH/bin/example.com
chulak ~/bla ^$ go install
chulak ~/bla ^$ go version $GOPATH/bin/example.com
/home/dominikh/prj/bin/example.com: go1.22.1
chulak ~/bla ^$ rm $GOPATH/bin/staticcheck
chulak ~/bla ^$ go install honnef.co/go/tools/cmd/staticcheck@v0.4.7
chulak ~/bla ^$ go version $GOPATH/bin/staticcheck
/home/dominikh/prj/bin/staticcheck: go1.21.8