Skip to content

Commit b87e9b9

Browse files
author
Jay Conrod
committed
cmd/go: clarify errors for commands run outside a module
The new error message tells the user what was wrong (no go.mod found) and directs them to 'go help modules', which links to tutorials. Fixes #44745 Change-Id: I98f31fec4a8757eb1792b45491519da4c552cb0f Reviewed-on: https://go-review.googlesource.com/c/go/+/298650 Trust: Jay Conrod <[email protected]> Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent a99ff24 commit b87e9b9

File tree

9 files changed

+47
-59
lines changed

9 files changed

+47
-59
lines changed

src/cmd/go/internal/modget/query.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (q *query) validate() error {
186186
if q.pattern == "all" {
187187
// If there is no main module, "all" is not meaningful.
188188
if !modload.HasModRoot() {
189-
return fmt.Errorf(`cannot match "all": working directory is not part of a module`)
189+
return fmt.Errorf(`cannot match "all": %v`, modload.ErrNoModRoot)
190190
}
191191
if !versionOkForMainModule(q.version) {
192192
// TODO(bcmills): "all@none" seems like a totally reasonable way to

src/cmd/go/internal/modload/import.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (e *ImportMissingError) Error() string {
5151
if e.isStd {
5252
return fmt.Sprintf("package %s is not in GOROOT (%s)", e.Path, filepath.Join(cfg.GOROOT, "src", e.Path))
5353
}
54-
if e.QueryErr != nil {
54+
if e.QueryErr != nil && e.QueryErr != ErrNoModRoot {
5555
return fmt.Sprintf("cannot find module providing package %s: %v", e.Path, e.QueryErr)
5656
}
5757
if cfg.BuildMod == "mod" || (cfg.BuildMod == "readonly" && allowMissingModuleImports) {
@@ -66,13 +66,11 @@ func (e *ImportMissingError) Error() string {
6666
return fmt.Sprintf("module %s provides package %s and is replaced but not required; to add it:\n\tgo get %s", e.replaced.Path, e.Path, suggestArg)
6767
}
6868

69-
suggestion := ""
70-
if !HasModRoot() {
71-
suggestion = ": working directory is not part of a module"
72-
} else {
73-
suggestion = fmt.Sprintf("; to add it:\n\tgo get %s", e.Path)
69+
message := fmt.Sprintf("no required module provides package %s", e.Path)
70+
if e.QueryErr != nil {
71+
return fmt.Sprintf("%s: %v", message, e.QueryErr)
7472
}
75-
return fmt.Sprintf("no required module provides package %s%s", e.Path, suggestion)
73+
return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
7674
}
7775

7876
if e.newMissingVersion != "" {
@@ -318,7 +316,11 @@ func importFromBuildList(ctx context.Context, path string, buildList []module.Ve
318316
return mods[0], dirs[0], nil
319317
}
320318

321-
return module.Version{}, "", &ImportMissingError{Path: path, isStd: pathIsStd}
319+
var queryErr error
320+
if !HasModRoot() {
321+
queryErr = ErrNoModRoot
322+
}
323+
return module.Version{}, "", &ImportMissingError{Path: path, QueryErr: queryErr, isStd: pathIsStd}
322324
}
323325

324326
// queryImport attempts to locate a module that can be added to the current

src/cmd/go/internal/modload/init.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func Init() {
177177
base.Fatalf("go: cannot find main module, but -modfile was set.\n\t-modfile cannot be used to set the module root directory.")
178178
}
179179
if RootMode == NeedRoot {
180-
base.Fatalf("go: cannot find main module; see 'go help modules'")
180+
base.Fatalf("go: %v", ErrNoModRoot)
181181
}
182182
if !mustUseModules {
183183
// GO111MODULE is 'auto', and we can't find a module root.
@@ -338,9 +338,11 @@ func die() {
338338
}
339339
base.Fatalf("go: cannot find main module, but found %s in %s\n\tto create a module there, run:\n\t%sgo mod init", name, dir, cdCmd)
340340
}
341-
base.Fatalf("go: cannot find main module; see 'go help modules'")
341+
base.Fatalf("go: %v", ErrNoModRoot)
342342
}
343343

344+
var ErrNoModRoot = errors.New("go.mod file not found in current directory or any parent directory; see 'go help modules'")
345+
344346
// LoadModFile sets Target and, if there is a main module, parses the initial
345347
// build list from its go.mod file.
346348
//

src/cmd/go/internal/modload/list.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func listModules(ctx context.Context, args []string, listVersions, listRetracted
7373
base.Fatalf("go: cannot use relative path %s to specify module", arg)
7474
}
7575
if !HasModRoot() && (arg == "all" || strings.Contains(arg, "...")) {
76-
base.Fatalf("go: cannot match %q: working directory is not part of a module", arg)
76+
base.Fatalf("go: cannot match %q: %v", arg, ErrNoModRoot)
7777
}
7878
if i := strings.Index(arg, "@"); i >= 0 {
7979
path := arg[:i]

src/cmd/go/internal/run/run.go

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -96,28 +96,12 @@ func runRun(ctx context.Context, cmd *base.Command, args []string) {
9696
base.Fatalf("go run: no go files listed")
9797
}
9898
cmdArgs := args[i:]
99-
if p.Error != nil {
100-
base.Fatalf("%s", p.Error)
101-
}
99+
load.CheckPackageErrors([]*load.Package{p})
102100

103-
p.Internal.OmitDebug = true
104-
if len(p.DepsErrors) > 0 {
105-
// Since these are errors in dependencies,
106-
// the same error might show up multiple times,
107-
// once in each package that depends on it.
108-
// Only print each once.
109-
printed := map[*load.PackageError]bool{}
110-
for _, err := range p.DepsErrors {
111-
if !printed[err] {
112-
printed[err] = true
113-
base.Errorf("%s", err)
114-
}
115-
}
116-
}
117-
base.ExitIfErrors()
118101
if p.Name != "main" {
119102
base.Fatalf("go run: cannot run non-main package")
120103
}
104+
p.Internal.OmitDebug = true
121105
p.Target = "" // must build - not up to date
122106
if p.Internal.CmdlineFiles {
123107
//set executable name if go file is given as cmd-argument

src/cmd/go/testdata/script/mod_convert_dep.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ stdout '^m$'
1818
# Test that we ignore directories when trying to find alternate config files.
1919
cd $WORK/gopkgdir/x
2020
! go list .
21-
stderr 'cannot find main module'
21+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
2222
! stderr 'Gopkg.lock'
2323

2424
-- $WORK/test/Gopkg.lock --

src/cmd/go/testdata/script/mod_find.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ rm go.mod
4949
# Test that we ignore directories when trying to find go.mod.
5050
cd $WORK/gomoddir
5151
! go list .
52-
stderr 'cannot find main module'
52+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
5353

5454
[!symlink] stop
5555

src/cmd/go/testdata/script/mod_outside.txt

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ stdout 'NUL|/dev/null'
1212
# 'go list' without arguments implicitly operates on the current directory,
1313
# which is not in a module.
1414
! go list
15-
stderr 'cannot find main module'
15+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
1616
go list -m
1717
stdout '^command-line-arguments$'
1818
# 'go list' in the working directory should fail even if there is a a 'package
1919
# main' present: without a main module, we do not know its package path.
2020
! go list ./needmod
21-
stderr 'cannot find main module'
21+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
2222

2323
# 'go list all' lists the transitive import graph of the main module,
2424
# which is empty if there is no main module.
@@ -41,7 +41,7 @@ stdout 'command-line-arguments'
4141

4242
# 'go list' on a package from a module should fail.
4343
! go list example.com/printversion
44-
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
44+
stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
4545

4646

4747
# 'go list -m' with an explicit version should resolve that version.
@@ -54,19 +54,19 @@ stdout 'v1.0.0\s+v1.0.1\s+v1.1.0'
5454

5555
# 'go list -m all' should fail. "all" is not meaningful outside of a module.
5656
! go list -m all
57-
stderr 'go: cannot match "all": working directory is not part of a module'
57+
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
5858

5959
# 'go list -m <mods> all' should also fail.
6060
! go list -m example.com/[email protected] all
61-
stderr 'go: cannot match "all": working directory is not part of a module'
61+
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
6262
! stdout 'example.com/version'
6363

6464
# 'go list -m' with wildcards should fail. Wildcards match modules in the
6565
# build list, so they aren't meaningful outside a module.
6666
! go list -m ...
67-
stderr 'go: cannot match "...": working directory is not part of a module'
67+
stderr 'go: cannot match "...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
6868
! go list -m rsc.io/quote/...
69-
stderr 'go: cannot match "rsc.io/quote/...": working directory is not part of a module'
69+
stderr 'go: cannot match "rsc.io/quote/...": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
7070

7171

7272
# 'go clean' should skip the current directory if it isn't in a module.
@@ -76,20 +76,20 @@ go clean -n
7676

7777
# 'go mod graph' should fail, since there's no module graph.
7878
! go mod graph
79-
stderr 'cannot find main module'
79+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
8080

8181
# 'go mod why' should fail, since there is no main module to depend on anything.
8282
! go mod why -m example.com/version
83-
stderr 'cannot find main module'
83+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
8484

8585
# 'go mod edit', 'go mod tidy', and 'go mod fmt' should fail:
8686
# there is no go.mod file to edit.
8787
! go mod tidy
88-
stderr 'cannot find main module'
88+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
8989
! go mod edit -fmt
90-
stderr 'cannot find main module'
90+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
9191
! go mod edit -require example.com/[email protected]
92-
stderr 'cannot find main module'
92+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
9393

9494

9595
# 'go mod download' without arguments should report an error.
@@ -104,33 +104,33 @@ exists $GOPATH/pkg/mod/cache/download/example.com/printversion/@v/v1.0.0.zip
104104

105105
# 'go mod download all' should fail. "all" is not meaningful outside of a module.
106106
! go mod download all
107-
stderr 'go: cannot match "all": working directory is not part of a module'
107+
stderr 'go: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
108108

109109

110110
# 'go mod vendor' should fail: it starts by clearing the existing vendor
111111
# directory, and we don't know where that is.
112112
! go mod vendor
113-
stderr 'cannot find main module'
113+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
114114

115115

116116
# 'go mod verify' should fail: we have no modules to verify.
117117
! go mod verify
118-
stderr 'cannot find main module'
118+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
119119

120120

121121
# 'go get' without arguments implicitly operates on the main module, and thus
122122
# should fail.
123123
! go get
124-
stderr 'cannot find main module'
124+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
125125
! go get -u
126-
stderr 'cannot find main module'
126+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
127127
! go get -u ./needmod
128-
stderr 'cannot find main module'
128+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
129129

130130
# 'go get -u all' upgrades the transitive import graph of the main module,
131131
# which is empty.
132132
! go get -u all
133-
stderr 'go get: cannot match "all": working directory is not part of a module'
133+
stderr '^go get: cannot match "all": go.mod file not found in current directory or any parent directory; see ''go help modules''$'
134134

135135
# 'go get' should check the proposed module graph for consistency,
136136
# even though we won't write it anywhere.
@@ -147,16 +147,16 @@ exists $GOPATH/pkg/mod/example.com/[email protected]
147147
# 'go build' without arguments implicitly operates on the current directory, and should fail.
148148
cd needmod
149149
! go build
150-
stderr 'cannot find main module'
150+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
151151
cd ..
152152

153153
# 'go build' of a non-module directory should fail too.
154154
! go build ./needmod
155-
stderr 'cannot find main module'
155+
stderr '^go: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
156156

157157
# 'go build' of source files should fail if they import anything outside std.
158158
! go build -n ./needmod/needmod.go
159-
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
159+
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
160160

161161
# 'go build' of source files should succeed if they do not import anything outside std.
162162
go build -n -o ignore ./stdonly/stdonly.go
@@ -179,7 +179,7 @@ go doc fmt
179179

180180
# 'go doc' should fail for a package path outside a module.
181181
! go doc example.com/version
182-
stderr 'doc: no required module provides package example.com/version: working directory is not part of a module'
182+
stderr 'doc: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
183183

184184
# 'go install' with a version should succeed if all constraints are met.
185185
# See mod_install_pkg_version.
@@ -194,7 +194,7 @@ stderr '^go install: version is required when current directory is not in a modu
194194
# 'go install' should fail if a source file imports a package that must be
195195
# resolved to a module.
196196
! go install ./needmod/needmod.go
197-
stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module'
197+
stderr 'needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
198198

199199
# 'go install' should succeed with a package in GOROOT.
200200
go install cmd/addr2line
@@ -206,12 +206,12 @@ stderr 'can only use path@version syntax with'
206206

207207
# 'go run' should fail if a package argument must be resolved to a module.
208208
! go run example.com/printversion
209-
stderr '^no required module provides package example.com/printversion: working directory is not part of a module$'
209+
stderr '^no required module provides package example.com/printversion: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
210210

211211
# 'go run' should fail if a source file imports a package that must be
212212
# resolved to a module.
213213
! go run ./needmod/needmod.go
214-
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: working directory is not part of a module$'
214+
stderr '^needmod[/\\]needmod.go:10:2: no required module provides package example.com/version: go.mod file not found in current directory or any parent directory; see ''go help modules''$'
215215

216216

217217
# 'go fmt' should be able to format files outside of a module.

src/go/build/build_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,7 @@ func TestImportPackageOutsideModule(t *testing.T) {
644644
ctxt.GOPATH = gopath
645645
ctxt.Dir = filepath.Join(gopath, "src/example.com/p")
646646

647-
want := "working directory is not part of a module"
647+
want := "go.mod file not found in current directory or any parent directory"
648648
if _, err := ctxt.Import("example.com/p", gopath, FindOnly); err == nil {
649649
t.Fatal("importing package when no go.mod is present succeeded unexpectedly")
650650
} else if errStr := err.Error(); !strings.Contains(errStr, want) {

0 commit comments

Comments
 (0)