Fix 'undefined' and 'undeclared name' Errors When Compiling Go

beginnerπŸ”· Go2026-03-18| Go 1.18+, any OS (Linux, macOS, Windows), go build / go run

Error Message

undefined: SomeVariable hoαΊ·c undeclared name: SomeFunction (khi biΓͺn dα»‹ch)
#go#compilation#undefined#undeclared

The Error

You run go build or go run and the compiler stops cold:

./main.go:12:5: undefined: SomeVariable
./main.go:20:10: undefined: SomeFunction
./utils.go:8:3: undeclared name: helperFunc

No warnings. No partial compilation. Just a hard stop. Go refuses to produce a binary when anything it references can't be found β€” and that's actually a feature, not a bug.

Why This Happens

Unlike Python or JavaScript, Go resolves every single name at compile time. A missing declaration isn't a runtime surprise β€” the compiler catches it immediately. That means typos, wrong packages, scope mistakes, and missing files all surface as undefined errors before your code ever runs.

The usual suspects:

  • Typo in the name (case counts β€” myFunc and MyFunc are different)
  • Missing import for a package you're calling
  • Variable declared inside a block, used outside it
  • Lowercase (unexported) name accessed from another package
  • File silently excluded by a build tag
  • Wrong package declaration in the file

Step-by-Step Fixes

1. Check for Typos First

Honest answer: this is the cause about 70% of the time. Go is case-sensitive, so myFunc, MyFunc, and myfunc are three completely different names.

// WRONG
result := myFuncion()  // typo: missing 't' in 'Function'

// RIGHT
result := myFunction()

Compare the spelling at both the declaration and the call site. In VS Code or GoLand, hover over the red underline β€” the tooltip usually shows the closest matching name, which makes the typo obvious immediately.

2. Check Your Imports

Call a function from another package without importing it, and Go reports it as undefined β€” even if the package is part of the standard library.

// WRONG β€” missing import
func main() {
    fmt.Println("hello")  // undefined: fmt
}

// RIGHT
import "fmt"

func main() {
    fmt.Println("hello")
}

The fastest fix is goimports:

goimports -w .

VS Code with the Go extension and GoLand both add missing imports on save automatically, so this problem mostly only bites people using plain text editors.

3. Check the Package Name, Not Just the Import Path

Here's a trap that catches people regularly: you import the right path, but call it by the wrong name.

import "math/rand"

// WRONG β€” the package name is 'rand', not 'math'
result := math.Intn(100)  // undefined: math

// RIGHT
result := rand.Intn(100)

The identifier you use is the package's name, not its import path. When they differ (like math/rand β†’ rand), check the package declaration at the top of the source file to see the actual name.

4. Check Scope β€” Is the Variable Where You Think It Is?

Block scoping in Go is strict. Declare a variable inside an if, for, or any {} block, and it simply doesn't exist outside that block.

// WRONG
if condition {
    result := compute()
}
fmt.Println(result)  // undefined: result

// RIGHT β€” declare before the block
var result int
if condition {
    result = compute()
}
fmt.Println(result)

The short declaration operator := is the sneaky part. Inside a block, result := compute() creates a brand-new variable scoped to that block. It looks like an assignment to an outer variable, but it isn't.

5. Exported vs Unexported Names Across Packages

Go's visibility rule is simple: uppercase first letter = exported (public), lowercase = unexported (package-private). Try to call an unexported name from outside its package and you get undefined.

// In package 'utils':
func helperFunc() string { ... }  // unexported β€” only visible inside 'utils'
func HelperFunc() string { ... }  // exported β€” visible everywhere

// In main.go:
utils.helperFunc()  // undefined: utils.helperFunc
utils.HelperFunc()  // OK

If you own the package, capitalize the name to export it. If it's a third-party package, look for an exported equivalent or a different API surface.

6. Files Excluded by Build Tags

A build tag can silently exclude a file from compilation. When that file contains declarations other files depend on, you get undefined with no obvious reason why.

//go:build linux

package mypackage

func PlatformSpecificFunc() { ... }

Build this on macOS or Windows and PlatformSpecificFunc doesn't exist as far as the compiler is concerned. Check for //go:build tags (or the older // +build syntax) at the top of files. To see exactly which files are included:

go list -f '{{.GoFiles}}' .
go list -f '{{.IgnoredGoFiles}}' .  # files excluded by build tags

7. Wrong Package Declaration in the File

Every .go file in a directory must declare the same package name (test files excluded). A single mismatched package line makes the compiler treat that file as belonging to a different package β€” so its declarations become invisible to its neighbors.

// file: utils.go
package util   // WRONG if your package is named 'utils'

// RIGHT
package utils

Run go vet ./... β€” it catches this and a handful of similar mismatches automatically.

8. Circular Imports Hiding Declarations

Go forbids circular imports entirely. If package A imports B and B imports A, both fail to compile. The error sometimes shows up as undefined for symbols in the imported package rather than a clear circular import message. Untangle the cycle by moving shared types into a third package that neither A nor B imports from each other.

Verify the Fix

Once you've made a change, do a clean rebuild to be sure:

# Wipe the build cache and rebuild everything
go clean -cache
go build ./...

# Or run directly
go run main.go

# Lint all packages in the module
go vet ./...

Clean output (no messages at all) means success. Still seeing errors? Read the compiler output carefully β€” it includes the exact file path and line number. It's never vague, and it always points to the right place.

Quick Checklist

  • Spelled the name exactly right, including case?
  • Imported the package that defines it?
  • Used the correct package alias (e.g., rand, not math)?
  • Declared the variable in the right scope?
  • Name is exported (uppercase) if used from another package?
  • No build tag quietly excluding the file?
  • All files in the directory share the same package name?

Useful Tools

# Auto-fix imports
goimports -w .

# Static analysis (catches many undefined-related mistakes)
go vet ./...
staticcheck ./...

# See exactly which files are compiled
go list -f '{{.GoFiles}}' .
go list -f '{{.IgnoredGoFiles}}' .  # files excluded by build tags

The gopls language server β€” used by VS Code, Vim/Neovim, and GoLand β€” highlights undefined names in real time, before you ever run the compiler. Set it up once and most of these errors get caught the moment you type them, not minutes later at build time.

Related Error Notes