./main.go:X:Y: undefined: functionName
The undefined: functionName error means the Go compiler cannot find the name you are using in the current scope. The one-line fix is to check spelling, ensure the package is imported, and verify the function is exported if it lives in another package.
The Full Error
./main.go:8:14: undefined: greet
Or across packages:
./main.go:12:5: undefined: utils.helper
The compiler tells you the file, line, and column where the unknown name appears. The name itself is everything after undefined:.
Cause 1: Simple Typo
The most frequent cause. Go is case-sensitive: Println and println are different names.
Broken code:
package main
import "fmt"
func main() {
fmt.Printl("hello") // typo: Printl instead of Println
}
Error:
./main.go:6:5: undefined: fmt.Printl
Fixed code:
package main
import "fmt"
func main() {
fmt.Println("hello") // correct spelling
}
How to find typos fast: Run go build ./... — the error line and column point you directly to the bad character. In VS Code with the Go extension, a red squiggle appears under the misspelled name before you even save.
Cause 2: Function Defined in a Different File — Same Package
If your function lives in another file in the same directory, it is automatically visible as long as both files declare package main (or the same package name). No import is needed.
Broken scenario: Two files, but one accidentally has a different package name.
helpers.go (broken):
package helpers // wrong — should be package main
func greet(name string) string {
return "Hello, " + name
}
main.go:
package main
import "fmt"
func main() {
fmt.Println(greet("world")) // undefined: greet
}
Fixed helpers.go:
package main // same package as main.go
func greet(name string) string {
return "Hello, " + name
}
Run with go run . (the dot) to include all .go files in the directory, not go run main.go which compiles only a single file.
Cause 3: Function Not Exported (Lowercase Name)
In Go, a name is exported (visible outside its package) only if it starts with an uppercase letter. A lowercase function name is private to its package.
utils/math.go (broken):
package utils
// lowercase — not exported, invisible outside this package
func add(a, b int) int {
return a + b
}
main.go:
package main
import (
"fmt"
"mymodule/utils"
)
func main() {
fmt.Println(utils.add(1, 2)) // undefined: utils.add
}
Error:
./main.go:9:18: undefined: utils.add
Note: the error says undefined, not "unexported". Go intentionally makes private names completely invisible — they do not exist from outside the package.
Fixed utils/math.go:
package utils
// Uppercase A — exported, visible to importing packages
func Add(a, b int) int {
return a + b
}
Fixed main.go:
package main
import (
"fmt"
"mymodule/utils"
)
func main() {
fmt.Println(utils.Add(1, 2)) // works: 3
}
Cause 4: Missing Import
If you use a package function without importing the package, you get undefined.
Broken code:
package main
func main() {
Println("hello") // undefined: Println — forgot import "fmt"
}
Or with the package name prefix but no import:
package main
func main() {
fmt.Println("hello") // undefined: fmt — import is missing
}
Fixed code:
package main
import "fmt"
func main() {
fmt.Println("hello")
}
Pro tip: Use goimports instead of gofmt. It automatically adds missing imports and removes unused ones every time you save. Install it once:
go install golang.org/x/tools/cmd/goimports@latest
Configure VS Code to use it:
{
"editor.formatOnSave": true,
"[go]": {
"editor.defaultFormatter": "golang.go"
},
"go.formatTool": "goimports"
}
Cause 5: Wrong Package Path or Alias
If you import a package under a different path than how you call it, the compiler sees an undefined name.
Broken code:
package main
import (
"fmt"
myrandom "math/rand" // aliased as myrandom
)
func main() {
fmt.Println(rand.Intn(100)) // undefined: rand — should use myrandom
}
Fixed code:
package main
import (
"fmt"
myrandom "math/rand"
)
func main() {
fmt.Println(myrandom.Intn(100)) // correct: use the alias
}
Or remove the alias:
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(rand.Intn(100)) // works
}
Cause 6: Circular Imports
Go forbids circular imports: package A cannot import package B if B already imports A. When a circular import exists, you typically see a cascade of undefined errors or an explicit:
import cycle not allowed
Broken structure:
myapp/
├── a/a.go (imports "myapp/b")
└── b/b.go (imports "myapp/a") ← circular!
Fix strategies:
- Extract shared code to a third package that neither A nor B imports:
myapp/shared - Merge the two packages if they are genuinely co-dependent
- Use an interface in the importing package instead of importing the concrete type
myapp/
├── a/a.go (imports "myapp/shared")
├── b/b.go (imports "myapp/shared")
└── shared/ (imported by both, imports neither)
Cause 7: Build Tag Excluding the File
A //go:build constraint at the top of a file can exclude it from the build entirely, making its functions invisible.
//go:build linux
package main
func platformHelper() string {
return "linux specific"
}
If you build on macOS or Windows, platformHelper is undefined because the file is excluded.
Fix: Either remove the build tag, provide a fallback file without the constraint, or build with the correct GOOS:
GOOS=linux go build ./...
Diagnosis Checklist
| Question | If yes → Fix |
|---|---|
| Is the name spelled correctly (including case)? | Fix the typo |
| Does the function live in another file with the same package name? | Run go run . not go run main.go |
| Does the function start with lowercase? | Capitalize it to export, or move caller into the same package |
| Is the package imported? | Add the import or run goimports |
| Is the package aliased? | Use the alias, not the last segment of the import path |
| Is there a build tag on the file containing the function? | Remove the tag or set correct GOOS/GOARCH |
| Does the error mention "import cycle"? | Refactor to remove the circular dependency |
FAQ
Q: Why does Go say undefined instead of "private" or "unexported"?
A: By design. From outside a package, private names do not exist at all — they are not visible, not accessible, and the compiler behaves as if they were never declared. This is different from languages like Java where private members are visible but access is checked.
Q: I added the import but still get undefined: pkg.FunctionName. What now?
A: Check three things: (1) the import path is the full module path, not just the package name — e.g., "github.com/user/repo/utils" not just "utils"; (2) the function name is exported (starts with uppercase); (3) you have run go mod tidy so the module is present in go.sum.
Q: Can I call a private function from a test file in the same package?
A: Yes. A test file named foo_test.go that declares package foo (not package foo_test) is part of the same package and can access all private names. This is Go's built-in white-box testing mechanism.