Skip to content

cmd/go: 'go work use' documentation is stale and contains typo #81807

Open

Description

@amanx5

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-config

What 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 use directive is added if the argument directory exists and removed if it does not exist.
  • Actual behavior: A use directive is only removed when the argument directory exists on disk but does not contain a go.mod file (Case B). When an argument directory does not exist on disk (Case C), the command errors out and leaves go.work completely 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

  1. Fix the typo in src/cmd/go/internal/workcmd/use.go by removing the extra "go.work file" after "command line".

  2. For the behavior discrepancy, either:

    • Option A (Update documentation to match implementation):
      Clarify that directives are added if the argument directory contains a go.mod file, 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.go via go generate cmd/go.

    • Option B (Update implementation to match documentation):
      Change go work use to drop the directive from go.work when the argument directory does not exist, rather than failing with directory ... does not exist.

      (Note: go work edit -dropuse=<dir> is already available for removing directives without requiring the directory to exist on disk).

  3. The following related documentation pages in golang/website will 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:

  1. Commit fdee1b297438 (Oct 2021) — Initial implementation:
    Originally, lookDir only checked os.Stat(filepath.Join(dir, "go.mod")) and did not validate whether dir itself existed on disk. If dir did not exist, os.IsNotExist matched and any matching directive in go.work was dropped without an error.

  2. 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".

  3. Commit a84ef500213e (Mar 2022, fixes #51749):
    Added a check for regular files (if target, err := fsys.Stat(useDir); err == nil && !target.IsDir()). If useDir did not exist at all, err != nil, so execution still fell through to lookDir(useDir) (preserving silent removal for non-existent directories).

  4. Commit 492c85ab84dc (Apr 2022, fixes #51841):
    Addressed an issue where go work use -r does_not_exist panicked with a nil pointer dereference inside fsys.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.

  5. 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.

  6. Commit 94982a07825a (Jul 2024, fixes #68245):
    Clarified the -r flag 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

  1. prattmic commented on Sep 29, 2026

    @prattmic
    Member

    cc @golang/command-line

  2. added
    NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.
    on Sep 29, 2026
  3. gopherbot commented on Oct 1, 2026

    @gopherbot
    Contributor

    Change https://go.dev/cl/843145 mentions this issue: cmd/go: describe when go work use adds and removes directives

  4. added a commit that references this issue on Oct 3, 2026
    5995b73
  5. added
    FixPendingIssues that have a fix which has not yet been reviewed or submitted.
    on Oct 16, 2026
  6. added this to the Go1.28 milestone on Oct 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    DocumentationIssues describing a change to documentation.FixPendingIssues that have a fix which has not yet been reviewed or submitted.NeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions