Go version

go version go1.24.3 darwin/arm64

Output of go env in your module/workspace:

AR='ar'
CC='cc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='c++'
GCCGO='gccgo'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/Users/anuraag/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/anuraag/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/vx/38td0k79201f9zn_myzbqx_40000gn/T/go-build645842018=/tmp/go-build -gno-record-gcc-switches -fno-common'
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/Users/anuraag/git/go-build/go.mod'
GOMODCACHE='/Users/anuraag/go/pkg/mod'
GONOPROXY='github.com/tetrateio/*'
GONOSUMDB='github.com/tetrateio/*'
GOOS='darwin'
GOPATH='/Users/anuraag/go'
GOPRIVATE='github.com/tetrateio/*'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/opt/homebrew/Cellar/go/1.24.3/libexec'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/anuraag/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/opt/homebrew/Cellar/go/1.24.3/libexec/pkg/tool/darwin_arm64'
GOVCS=''
GOVERSION='go1.24.3'
GOWORK='/Users/anuraag/git/go-build/go.work'
PKG_CONFIG='pkg-config'

What did you do?

go tool -modfile build/tools/golangci-lint/go.mod golangci-lint run -h

Note, go.work does not include ./build/tools/golangci-lint. build/tools/golangci-lint/go.mod contains single tool github.com/golangci/golangci-lint/v2/cmd/golangci-lint and the dependencies added by go mod tidy.

What did you see happen?

go: -modfile cannot be used in workspace mode

What did you expect to see?

Tool runs normally. I would like to use separate mod files for tools to protect against dependency conflicts. Unfortunately, -modfile cannot be used in a workspace (#59996).

It does work if specifying GOWORK=off, but for tools that build Go code, such as golangci-lint (or perhaps opentelemetry-go-autoinstrumentation, etc), this causes the downstream tool invocation to inherit the variable and generally not work if the workspace settings are required to build the code. It seems like it should be possible to run tools with isolated modfiles within a workspace.

A couple of ideas

  • Respect -modfile specifically for the tool command if the tool module is not in the workspace (my current issue is specific to tool but the same may apply to run instead of blocking the flag completely like now). IIUC #59996 correctly, the corner case is specifically running a workspace module with the flag set and there wouldn't be problems for modules not defined in the workspace?

  • Add a command line flag with the same semantics as GOWORK, e.g. go tool -gowork off -modfile tools/golangci-lint/go.mod run. This would allow configuring go tool without affecting the downstream invocation. Unfortunately, the best named -work flag is already taken.

Comment From: gabyhelp

Related Issues

Related Code Changes

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

Comment From: matloob

One of the principles of the way the tool directive was designed is that the tools go in the same module graph as the rest of your code. That does mean that there are some cases where you'd have to build the tool using go build, perhaps in another workspace before you run it.

We could have gone with another design, but given that this is the way it works now, adding multiple ways of specifying the module graph could just make things more complex, and we'd need to hear a compelling justification to do so.

Comment From: anuraaga

@matloob But tool supports the -modfile flag which is now also fully documented

https://github.com/golang/go/commit/b574590c36b7ede1492239db2d55c35e8818c7a7

So already there are multiple ways of specifying the module graph right? This is good since there can otherwise be some dependency conflicts.

This issue is mostly about that not working in workspace mode though it seems like it should, not adding a new mechanism for the dependency graph.