Fix Go "package is not in GOROOT" and "cannot find package"

Deepak Prasad
Tested on RHEL 10.2 with Go 1.27.0
Package go 1.27.0
Applies to Any host with Go 1.20+ installed
Privilege Normal user
Scope Import resolution for local packages, external modules, sibling modules with go.work or replace, and legacy GOPATH mode. Does not cover private module authentication, vendoring, or a full Go modules tutorial.
Related guides Create a Go module
go.mod file not found
Import local package without GOPATH
GOPATH vs GOROOT
Golang tutorial

go build, go test, and go install can stop with several related messages:

text
cannot find package "..."
package example/foo is not in std
no required module provides package example/foo
cannot find module providing package example/foo

Setting GOPATH does not normally make an arbitrary directory importable when Go is operating in module mode. Start by checking which module or workspace Go selected and whether the import path matches that layout.

Situation First thing to check
Local package in same project go.mod module path + package directory
External dependency Import path + go get / go mod tidy
Another local module go.work or local replace
GOPATH-era project $GOPATH/src/<import-path> and active mode
Standard package like fmt not found Go installation / GOROOT

Check which module or workspace Go is using

Before you rename folders or export more environment variables, ask the Go command what context it selected from your current directory:

bash
go env GOMOD GOWORK GOPATH GOROOT GO111MODULE

Sample output from a normal module project (values vary by machine):

output
/tmp/go-demo-import/go.mod

/root/go
/usr/local/go

GOMOD shows the go.mod file selected for the current directory. An empty value or /dev/null on Unix means Go did not find a module on the upward path—cd into the module tree or see go.mod file not found.

GOWORK shows an active workspace file when one applies. When GOWORK is empty, no workspace is active, so the current module context governs package resolution.

GOPATH supplies the default module-cache location unless GOMODCACHE is set, and the default binary-install location unless GOBIN is set. It also backs legacy GOPATH development mode. In module-aware builds it does not define your normal project import-path hierarchy.

GOROOT points at the Go installation and standard library. Do not change GOROOT manually as a routine import fix.

GO111MODULE is usually empty on current toolchains because module mode is the default. Legacy GOPATH development mode can still be selected explicitly when maintaining old projects, but it is not the recommended fix for a modern module layout.


Fix a local package in the same Go module

This is the most common case: code in the same repository, but the import string does not line up with go.mod and the directory tree.

Example layout:

text
demo/
├── go.mod
├── main.go
└── boo/
    └── boo.go

go.mod:

text
module example.com/demo

go 1.21

boo/boo.go:

go
package boo

import "fmt"

func Boo() {
	fmt.Println("This is the Boo function")
}

main.go:

go
package main

import (
	"fmt"

	"example.com/demo/boo"
)

func main() {
	boo.Boo()
	fmt.Println("This is the main call")
}

For a package inside the same module, its import path is normally the module path from go.mod plus the package directory relative to the module root. Here that is example.com/demo/boo, not boo alone.

Package names conventionally match the final directory element, but what matters structurally is the import path and that every non-test .go file in one directory belongs to a single valid package. You cannot put package main in main.go and package boo in boo.go in the same directory and treat them as separate packages—give boo its own folder.

From the demo directory, run the module:

bash
go run .

Sample output:

output
This is the Boo function
This is the main call

Typical local mistakes:

  • Importing boo instead of example.com/demo/boo
  • Leaving boo.go beside main.go while the code still says package boo
  • Using a module prefix in import that does not match the module line in go.mod

go mod tidy synchronizes module requirements with imports in your source. It cannot repair a wrong local directory layout or a mismatched import prefix—fix the tree first, then tidy if external dependencies changed.


Fix "no required module provides package"

When the missing code is an external module, Go reports something like:

text
no required module provides package example.com/lib/foo; to add it:
	go get example.com/lib/foo

First confirm the import path is spelled correctly and matches how the dependency is published. A typo looks like a missing module.

When you genuinely need that package, add the requirement:

bash
go get example.com/lib/foo

Or run:

bash
go mod tidy

when your source already imports the dependency and you want go.mod and go.sum synchronized. go mod tidy adds missing module requirements needed by packages in the module and removes unnecessary ones—it does not invent a local folder that was never on disk.


Use another local module with go.work or replace

Two modules on disk need an explicit link during development:

text
workspace/
├── app/
│   ├── go.mod
│   └── main.go
└── library/
    ├── go.mod
    └── foo/
        └── foo.go

app/go.mod might say module example.com/app and import example.com/library/foo. Without a workspace, go build in app/ fails because the library is not in the public module proxy.

The modern fix for active development is a workspace at a parent directory:

bash
go work init ./app ./library

Both modules keep their own module paths. The workspace tells the Go command to use those local trees together. From app/, go build . and go run . then resolve example.com/library/foo from the sibling module.

Alternatively, in app/go.mod add both a requirement and a replace directive. A replace alone does not add the module to the dependency graph—the module must also be required:

text
require example.com/library v0.0.0

replace example.com/library => ../library

After adding the local replace, run go mod tidy with the import present; it can add the matching require entry. You can also add the require line explicitly. You still need the replace to point at the local directory.

replace substitutes one module path with a local directory for that module. Use go.work when several modules change together; use replace when one consumer needs a local fork. Import the module path from go.mod, never a raw filesystem path in the import string.


Why "package X is not in std" appears

When Go sees:

go
import "foo/bar"

and cannot resolve it from the selected module, workspace, or dependencies, some toolchains phrase the failure as:

text
package foo/bar is not in std (...)

That does not automatically mean GOROOT is corrupted. The usual checks are:

  1. Is the import path spelled correctly?
  2. Does it include the full module prefix for local code?
  3. Are you inside the intended module or workspace?
  4. Is an external dependency actually required and downloadable?

Only investigate a damaged Go installation if even genuine standard packages such as fmt, net/http, or os cannot be found. For that situation, verify go env GOROOT and reinstall the toolchain if the standard library tree is missing.


Legacy GOPATH mode: when $GOPATH/src still matters

Module mode is the default and recommended workflow. Legacy GOPATH development mode still exists when explicitly selected and is what the slug on this page refers to.

In GOPATH development mode, an import:

go
import "example.com/me/project/foo"

is expected under:

text
$GOPATH/src/example.com/me/project/foo

Exporting GOPATH=/some/path alone is insufficient if the source tree does not follow that layout. If you maintain an old GOPATH-only project, confirm the code lives under $GOPATH/src/<import-path> and that you are deliberately using GOPATH mode—not flipping GO111MODULE=off on a modern module tree as a shortcut.

For new work, initialize a module with go mod init and match import paths to the module line. See create a Go module for naming conventions.


Common package-resolution mistakes

Symptom Likely issue
package X is not in std Import path does not resolve in selected module or workspace
no required module provides package X External requirement missing or import path wrong
Local package cannot be imported Module prefix or directory path is wrong
Works in one directory but not another Different GOMOD / GOWORK selection
Setting GOPATH changes nothing Build is using modules
Sibling module cannot be found Add it to go.work or use replace
Even fmt cannot be found Investigate Go installation / GOROOT
GOPATH project still fails Check $GOPATH/src/<import-path> and active mode

Summary

Go import errors look different on the surface, but they share one question: why could the toolchain not map your import line to a real package? Start with go env GOMOD and go env GOWORK so you know which module or workspace is active, then match local imports to the module path plus directory layout.

For code outside your module, add a real dependency with go get or synchronize requirements with go mod tidy after the import path is correct. For a sibling module on disk, wire it with go work or a replace directive instead of expecting GOPATH to bridge the gap.

Module mode is the default modern workflow. GOPATH still backs the module cache and installed tools, but it does not replace go.mod for normal projects. Treat legacy GOPATH layout as intentional maintenance of older trees, not the first fix when a module import fails.


References


Frequently Asked Questions

1. Why is my Go package "not in GOROOT" even though GOPATH is set?

GOROOT holds the standard library. That message means Go did not resolve the import from your active module, workspace, or dependencies—not that GOPATH was forgotten. Setting GOPATH does not make an arbitrary folder importable in module mode.

2. Does Go still use GOPATH in current versions?

Yes, but mainly for the module download cache, installed binaries when GOBIN is unset, and legacy GOPATH development mode. Module mode is the default workflow; GOPATH no longer defines your normal project import hierarchy.

3. What does "package X is not in std" mean?

Go could not resolve the import path from the selected module, workspace, or dependencies, so it reports that the package is not in the standard library. Check spelling, module prefix, workspace membership, and external requirements before suspecting a broken Go install.

4. How do I import a local package from the same module?

Put the package in its own directory under the module root and import module-path-from-go.mod plus the relative directory path. All non-test Go files in that directory must belong to one valid package.

5. How do I use another local module without publishing it?

Add both modules to a go.work workspace for active development, or add a replace directive in go.mod that points at the local module directory. Import the module path from go.mod, not a filesystem path.

6. Should I set GO111MODULE=off to fix "cannot find package"?

Generally no. Turning modules off is a legacy diagnostic choice for old GOPATH layouts, not the normal fix for a modern project with a wrong import path or missing dependency.

7. What is the difference between GOPATH and GOROOT?

GOROOT is the Go toolchain and standard library installation. GOPATH is a workspace root used for module cache and binaries, and for legacy GOPATH-mode source trees under GOPATH/src. Neither replaces a correct go.mod import path in module mode.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms.

  • Go (programming language)
  • Python (programming language)
  • Java (programming language)
  • MongoDB
  • Kubernetes