When go build or go install stops with “cannot find package” or “package … is not in GOROOT” (sometimes mentioning GOROOT or GOPATH), it almost always means Go cannot match your import line to any real folder it is allowed to use—not that your GOPATH environment variable forgot to turn on. People still hit this after setting GOPATH because imports today are ruled mainly by modules (go.mod) and the directory tree under your project, not by a loose file sitting somewhere under src.
This guide walks through what that message is trying to tell you, how to fix layout under Go modules (the path you should use today), and a couple of related errors that show up in the same searches (including “cannot use -o with multiple packages”).
If you are new to modules, import local package without GOPATH is a good companion read.
Tested with Go 1.26.4 linux/amd64 on Linux kernel 6.14.0-37-generic.
Understanding “cannot find package” and “not in GOROOT”
GOROOT is where Go keeps the standard library (fmt, net/http, and so on). When the compiler says a package is “not in GOROOT,” it is not accusing you of a broken Go install; it is saying this import is not a built-in package, and Go still has not found it anywhere else it is allowed to look.
In module mode (the default for years, and the only mode on current Go versions), “anywhere else” means roughly: other packages in your module, other modules listed in go.mod, and the module download cache—not “any folder on disk you happen to like.”
So searches like “cannot find package in goroot,” “package is not in goroot,” or “cannot find package in goroot or gopath” all point to the same troubleshooting job: line up your import path with a real directory and a correct go.mod module line.
Fixes, layout, and related errors
Put your code in a folder with a go.mod file. The module line is the prefix of every import inside that tree.
The in-site Run control sends one program string to the Go Playground. The demo/ example below is two packages on disk (package boo in boo/boo.go and package main importing demo/boo). That cannot compile as a single Playground paste, so those Go fences use {run=false}—create the files and use go run . locally. A self-contained package main that only imports the standard library does get Run:
package main
import "fmt"
func main() {
fmt.Println("When imports resolve, the compiler is happy—this program only needs the stdlib.")
}If you use Run on that snippet, you should see one line of printed output from fmt.Println.
Example layout:
demo/
go.mod # module demo
main.go
boo/
boo.go # package boogo.mod:
module demo
go 1.21boo/boo.go:
package boo
import "fmt"
func Boo() {
fmt.Println("This is the Boo function")
}main.go:
package main
import (
"demo/boo"
"fmt"
)
func main() {
boo.Boo()
fmt.Println("This is the main call")
}From the demo directory:
go run .After go run . from the demo root you should see the Boo line first, then the line from main.
Typical mistakes that reproduce “go cannot find package” or “golang cannot find package”:
main.gocallsboo.Boo()but there is noimport "demo/boo"(or whatever your module prefix is).boo.gosits next tomain.gowhile the code still sayspackage boo—the folder name andpackageline should match, and the file should live underboo/, not besidemainunless you intentionally usepackage mainin one file only.- The import uses
myproject/boobutgo.modsaysmodule github.com/you/myproject—the prefix inimportmust match themodulepath plus subfolders.
After you move files, run:
go mod tidy…so missing requirements are recorded or stale entries are cleaned up.
go build and go install
go build and go install both resolve imports the same way. If you see go build report “cannot find package” (or the same from go install), apply the same layout checks as above. go install additionally writes a binary to GOBIN or GOPATH/bin when the build succeeds—it does not magically find packages GOPATH could not see.
Dot imports, replace, and “cannot find package . …”
A dot import (import . "some/pkg") or a bad relative path often triggers confusing errors. Prefer normal imports (import "module/subpkg") until you are comfortable with the rules. If you truly need a local path outside the module, add a replace directive in go.mod pointing at a folder on disk, then import the module path you replaced—not a raw filesystem path in the import string.
go build -o with multiple packages
If you run something like:
go build -o mytool ./cmd/foo ./cmd/barGo may report:
go: cannot use -o with multiple packagesYou asked for one output file name (-o) but listed more than one package. Build one main package at a time, for example:
go build -o mytool ./cmd/foo…or drop -o and build each package separately.
Legacy GOPATH note
Long ago, people put everything under $GOPATH/src/import/path. Current Go expects modules for new work. Setting GOPATH alone does not make import "boo" work unless the source really lives at $GOPATH/src/boo and you are still on a workflow that uses GOPATH mode—which modern toolchains no longer emphasize.
If you maintain very old material, the official note on defaults is Go 1.16 module changes. For day-to-day fixes, treat a correct go.mod plus matching import paths as the real answer—not flipping historical environment variables.
Summary
“Cannot find package” and “not in GOROOT” mean the import string did not resolve to a real package: fix the module path in go.mod, put code under folders that match package names, add the correct import, and run go mod tidy. go build and go install fail the same way when imports are wrong. If you see “cannot use -o with multiple packages,” you passed more than one package to a command that only allows one output binary name. Modern Go is module-first; do not expect GOPATH alone to fix a mismatched import.
References
- Go 1.16 module changes (go.dev blog)
- Create a Go module — tutorial
- Developing a major version of a module

