The Go compiler is refusing to allow your program to import packages marked as internal.
This error, "use of internal package not allowed," means you’re trying to import a package located within a directory named internal from a project outside of that internal directory’s parent. Go’s build system has a security and encapsulation feature where anything under an internal directory can only be imported by code within that internal directory’s parent or any subdirectory thereof. It’s designed to prevent accidental or unauthorized reliance on implementation details of a library.
Here are the common reasons this happens and how to fix them:
1. Incorrect Package Structure
Diagnosis: You’ve placed a package that should be public within an internal directory, or you’ve accidentally created an internal directory where it doesn’t belong in your project hierarchy.
Check:
Examine your project’s directory structure. If you have a file like myproject/internal/mylib/mylib.go and you’re trying to import "myproject/internal/mylib" from myproject/other/main.go, this is the problem. The internal directory must be a sibling or ancestor of the directory you’re importing from.
Fix:
If mylib is intended to be a public API for your project, move it out of the internal directory.
# Example: Move mylib from internal to the root of the package
mv myproject/internal/mylib/ myproject/mylib/
This allows any part of myproject to import myproject/mylib.
Why it works: By removing the internal directory, you remove the restriction, allowing imports from any path within the myproject module.
2. Importing an Internal Package from Another Module
Diagnosis: You’re trying to import an internal package from a different Go module than the one containing the internal directory. This is the most common scenario where the error is correctly triggering.
Check: Let’s say you have two modules:
github.com/user/projectAwithgithub.com/user/projectA/internal/utilsgithub.com/user/projectBwhich tries toimport "github.com/user/projectA/internal/utils"
The Go toolchain will see that projectB is not within the hierarchy of projectA (i.e., projectB is not projectA or a subdirectory of projectA).
Fix:
The internal package is only for use within the module that defines it. If utils is meant to be shared, it cannot reside in an internal directory. Move utils to a non-internal location within projectA.
# On your machine, navigate to projectA's root
cd path/to/github.com/user/projectA
# Move the internal package to a public location
mv internal/utils/ public/utils/
Then, update the import path in projectA’s code (if necessary) and ensure projectB now imports the public path:
// In projectB/main.go
import "github.com/user/projectA/public/utils" // Assuming projectA has a go.mod defining its module path
Why it works: The internal restriction is module-aware and directory-hierarchy-aware. By moving the package out of internal, you make it a standard, importable package within its module.
3. Incorrect Module Path Definition
Diagnosis: Your go.mod file might be defining a module path that doesn’t accurately reflect your project’s intended root, leading the Go toolchain to incorrectly determine parent-child relationships between packages.
Check:
Look at your go.mod file. If your project is at /home/user/go/src/github.com/user/myproject and your go.mod says module myproject, the Go toolchain might have trouble resolving paths like myproject/internal/... correctly, especially if myproject isn’t the top-level directory in your GOPATH or module cache.
Fix:
Ensure your go.mod’s module directive matches the actual root of your repository or project that you intend to import from. If your module is github.com/user/myproject, your go.mod should start with module github.com/user/myproject.
// go.mod
module github.com/user/myproject
go 1.20
// ... other directives
Then, ensure your directory structure aligns with this. If you have github.com/user/myproject/internal/utils, you should be able to import github.com/user/myproject/internal/utils from github.com/user/myproject/cmd/myapp.
Why it works: The go.mod file establishes the module’s identity. A correct module path is crucial for the Go toolchain to correctly interpret package paths and enforce the internal directory rules based on the defined module root.
4. Using go install or go run on an Internal Package Directly
Diagnosis: You’re trying to build or run an internal package as a main executable, or you’re using go install on an internal package from outside its parent directory.
Check:
If you have myproject/internal/myapp/main.go and you run go install myproject/internal/myapp from myproject/other/, or go run myproject/internal/myapp from myproject/other/, you’ll hit this.
Fix:
An internal package is not meant to be a top-level entry point for installation or execution. If myapp is a program, it should not be in an internal directory. Move it to a non-internal directory like cmd/myapp or apps/myapp.
# Example: Move myapp from internal to cmd
mv myproject/internal/myapp/ myproject/cmd/myapp/
Then you can build/run it correctly: go install myproject/cmd/myapp or go run myproject/cmd/myapp.
Why it works: The internal restriction applies to imports. Making an internal package a top-level executable bypasses the import mechanism, but the Go toolchain correctly identifies that an internal package shouldn’t be exposed as a standalone installable artifact from outside its module hierarchy.
5. Tooling Configuration Issues (Less Common)
Diagnosis: In rare cases, older or misconfigured build tools, IDEs, or custom build scripts might not correctly interpret Go’s internal package rules, leading to this error even when the Go toolchain itself would be fine.
Check:
Try building your project using the standard go build or go run commands from your terminal. If they work, but your IDE or CI/CD pipeline shows the error, the issue is with that specific tool’s configuration.
Fix: Update your IDE’s Go plugin, ensure your build scripts are using up-to-date Go commands, or configure your CI/CD environment to use a recent Go version. For IDEs, sometimes invalidating caches and restarting can resolve these issues.
Why it works: This ensures that the build environment is respecting the standard Go build rules, including the internal package visibility.
6. Forgetting to Commit Changes to go.mod
Diagnosis: You’ve moved a package out of internal and updated your imports, but you forgot to go mod tidy or commit the changes to your go.mod file. The build system is still operating on old module information.
Check:
Run go mod tidy in your module root. If it adds or removes lines from go.mod, or if go.mod doesn’t reflect the current state of your internal vs. public packages, this is the problem.
Fix:
Run go mod tidy in the root of your module. This cleans up unused dependencies and ensures go.mod reflects the current import graph.
# In the root of your module (where go.mod is)
go mod tidy
git add go.mod go.sum
git commit -m "Tidy module dependencies"
Why it works: go mod tidy synchronizes your go.mod file with the actual imports in your code, ensuring the build system has accurate information about package availability.
The next error you’ll likely encounter after fixing these is a package not found error if you’ve moved a package and haven’t updated all the import statements pointing to it.