Repository navigation
cmd/go: 'go work use' documentation is stale and contains typo #81807
Description
Go version
go version go1.28-devel_2ff5743d9f Sat Sep 26 15:27:19 2026 -0700 windows/amd64 (and all supported releases since Go 1.18.1)
Output of go env in your module/workspace:
set AR=ar
set CC=gcc
set CGO_CFLAGS=-O2 -g
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-O2 -g
set CGO_ENABLED=1
set CGO_FFLAGS=-O2 -g
set CGO_LDFLAGS=-O2 -g
set CXX=g++
set GCCGO=gccgo
set GO111MODULE=
set GOAMD64=v1
set GOARCH=amd64
set GOAUTH=netrc
set GOBIN=C:\Users\aman\go\bin
set GOCACHE=C:\Users\aman\AppData\Local\go-build
set GOCACHEPROG=
set GODEBUG=
set GOENV=C:\Users\aman\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFIPS140=off
set GOFLAGS=
set GOGCCFLAGS=-m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=C:\Users\aman\AppData\Local\Temp\go-build3356099773=/tmp/go-build -gno-record-gcc-switches
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMOD=NUL
set GOMODCACHE=C:\Users\aman\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPACKAGESDRIVER=
set GOPATH=C:\Users\aman\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=U:\GoogleSource\go
set GOSUMDB=sum.golang.org
set GOTELEMETRY=local
set GOTELEMETRYDIR=C:\Users\aman\AppData\Roaming\go\telemetry
set GOTMPDIR=
set GOTOOLCHAIN=auto
set GOTOOLDIR=U:\GoogleSource\go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.28-devel_2ff5743d9f Sat Sep 26 15:27:19 2026 -0700
set GOWORK=
set PKG_CONFIG=pkg-configWhat did you do?
-
Check the Add modules to workspace file section in the Go command documentation page (generated from
src/cmd/go/internal/workcmd/use.go):The documentation currently states:
A use directive will be added to the go.work file for each argument
directory listed on the command line go.work file, if it exists,
or removed from the go.work file if it does not exist. -
Verify the documented behavior with a sample workspace:
# create workspace with three modules mkdir workspace && cd workspace mkdir a && cd a && go mod init a && cd .. mkdir b && cd b && go mod init b && cd .. mkdir c && cd c && go mod init c && cd .. go work init a b c # Case A: Argument directory exists and contains go.mod go work use a # Case B: Argument directory exists but does not contain go.mod rm b/go.mod go work use b # Case C: Argument directory does not exist on disk rm -r c # in powershell: rm -Recurse c go work use c
What did you see happen?
Case A (go work use a)
The use a directive is retained in go.work (exit code 0).
Case B (go work use b)
Even though the directory exists, the use b directive is removed from go.work (exit code 0) because removal is governed by the absence of go.mod, which is not mentioned in the documentation.
Case C (go work use c)
The documentation states that the directive will be removed from go.work if the argument directory does not exist. But the command fails with an error:
$ go work use c
go: directory c does not exist
go: open U:\workspace\c\go.mod: The system cannot find the path specified.The command exits with exit code 1 without modifying go.work. The use c directive is not removed:
go 1.22
use (
a
c
)
Summary
- Documented behavior: A
usedirective is added if the argument directory exists and removed if it does not exist. - Actual behavior: A
usedirective is only removed when the argument directory exists on disk but does not contain ago.modfile (Case B). When an argument directory does not exist on disk (Case C), the command errors out and leavesgo.workcompletely unmodified. - Typo:
"directory listed on the command line go.work file, if it exists"has an extra"go.work file"after"command line".
What did you expect to see?
Expected either the documentation to accurately reflect the actual implementation (along with fixing the typo), or the implementation to match the documented behavior:
Proposed Solution
-
Fix the typo in
src/cmd/go/internal/workcmd/use.goby removing the extra"go.work file"after"command line". -
For the behavior discrepancy, either:
-
Option A (Update documentation to match implementation):
Clarify that directives are added if the argument directory contains ago.modfile, or removed if it does not:A use directive will be added to the go.work file for each argument - directory listed on the command line go.work file, if it exists, - or removed from the go.work file if it does not exist. + directory listed on the command line, if it contains a go.mod file, + or removed from the go.work file if it does not.
Regenerate
alldocs.goviago generate cmd/go. -
Option B (Update implementation to match documentation):
Changego work useto drop the directive fromgo.workwhen the argument directory does not exist, rather than failing withdirectory ... does not exist.(Note:
go work edit -dropuse=<dir>is already available for removing directives without requiring the directory to exist on disk).
-
-
The following related documentation pages in
golang/websitewill also need to be updated with the revised description:
Analysis
Inspecting src/cmd/go/internal/workcmd/use.go (function workUse) and verifying with runtime tests shows how each case is handled:
| Scenario | Command Behavior | Effect on go.work |
Exit Code |
|---|---|---|---|
Case A: Directory exists with valid go.mod (go work use a) |
lookDir finds go.mod, checks that it is regular, and records it in keepDirs (L128). |
Adds or keeps the use directive via wf.AddUse. |
0 |
Case B: Directory exists, but has no go.mod (go work use b) |
lookDir encounters os.IsNotExist for go.mod and sets keepDirs[absDir] = "" (L113). |
Removes directive. If b was in go.work, wf.DropUse removes it. |
0 |
Case C: Directory does not exist on disk (go work use c) |
Fails with go: directory c does not exist (L138-L140, L227). |
None. Even if c was previously in go.work, the command exits before saving the file. |
1 |
Recursive flag (go work use -r <dir>) |
<dir> must exist. Subdirectories are walked recursively via fsys.WalkDir. |
Adds directories containing go.mod. Drops directories without go.mod. Also removes subdirectories under <dir> that previously existed in go.work but were deleted from disk (L178-L184). |
0 |
History
Click to expand related commit history
Tracing the history of src/cmd/go/internal/workcmd/use.go:
-
Commit
fdee1b297438(Oct 2021) — Initial implementation:
Originally,lookDironly checkedos.Stat(filepath.Join(dir, "go.mod"))and did not validate whetherdiritself existed on disk. Ifdirdid not exist,os.IsNotExistmatched and any matching directive ingo.workwas dropped without an error. -
Commit
0c24038d22a8(Dec 2021) — Initial documentation:
The command documentation was added to reflect the initial behavior:"A use directive will be added to the go.work file for each argument directory listed on the command line go.work file, if it exists on disk, or removed from the go.work file if it does not exist on disk."
This commit also introduced the repeated phrase
"command line go.work file". -
Commit
a84ef500213e(Mar 2022, fixes #51749):
Added a check for regular files (if target, err := fsys.Stat(useDir); err == nil && !target.IsDir()). IfuseDirdid not exist at all,err != nil, so execution still fell through tolookDir(useDir)(preserving silent removal for non-existent directories). -
Commit
492c85ab84dc(Apr 2022, fixes #51841):
Addressed an issue wherego work use -r does_not_existpanicked with a nil pointer dereference insidefsys.Walk.fsys.Stat(absArg)was moved up front for all arguments:info, err := fsys.Stat(absArg) if err != nil { if os.IsNotExist(err) { base.Errorf("go: directory %v does not exist", absArg) } else { base.Errorf("go: %v", err) } continue }
Passing a non-existent directory argument became an error that halts execution via
base.ExitIfErrors(). The command documentation was not updated at the time to reflect this change. -
Commit
ce8146ed3361(Jun 2023):
Added toolchain switching and updated the documentation for Go versions and "fails if any remaining use directives refer to modules that do not exist". The phrase"if it exists on disk"was shortened to"if it exists", but the first sentence and the"command line go.work file"wording remained. -
Commit
94982a07825a(Jul 2024, fixes #68245):
Clarified the-rflag description by removing the second clause ("namely, use directives will be added for directories that exist, and removed for directories that do not exist"). The first paragraph remained unchanged.
Activity
prattmic commentedon Sep 29, 2026
cc @golang/command-line
gopherbot commentedon Oct 1, 2026
Change https://go.dev/cl/843145 mentions this issue:
cmd/go: describe when go work use adds and removes directivescmd/go: describe when go work use adds and removes directives