goseverity: blocker
runtime error: invalid memory address or nil pointer dereference

Go nil pointer dereference — runtime error: invalid memory address

nil pointer dereference

97% fixable~10 mindifficulty: beginner

Verified against Go spec: Address operators, Go blog: Error handling and Go, Effective Go: Pointers vs Values · Updated June 2026

> quick_fix

Your code is accessing a field or calling a method on a pointer variable that is nil. The stack trace in the panic message names the exact file and line. Add a nil check before dereferencing any pointer returned from a function that can return nil.

// Panics if user is nil
func greet(user *User) string {
    return "Hello, " + user.Name  // panic: nil pointer dereference
}

// Fixed — nil guard
func greet(user *User) string {
    if user == nil {
        return "Hello, Guest"
    }
    return "Hello, " + user.Name
}

What causes this error

In Go, pointer types, interfaces, maps, slices, channels, and function values default to nil. Accessing a field, calling a method, or indexing a nil value causes a runtime panic with 'invalid memory address or nil pointer dereference'. Common sources: a function returning `*T, error` where the caller ignores the error and uses the nil `*T`; an interface value holding a nil concrete type; an uninitialized struct with pointer fields.

> advertisementAdSense placeholder

How to fix it

  1. 01

    step 1

    Read the panic stack trace to find the exact line

    Go's panic output includes a full goroutine stack trace with file names and line numbers. The line causing the dereference is the topmost frame in your own package (skip the runtime frames).

    # Panic output example:
    # goroutine 1 [running]:
    # main.greet(...)
    #     /app/main.go:15 +0x...  ← this is your line
    # main.main()
    #     /app/main.go:8 +0x...
    
    # Run with full stack trace
    GOTRACEBACK=all go run main.go
  2. 02

    step 2

    Check if an error was ignored after a function returning (*T, error)

    The most common cause: `obj, _ := getObject()` where `getObject` returned `nil, err`. The underscore discards the error and `obj` is nil. Always check the error before using the result.

    // BAD — ignoring error, using potentially nil obj
    obj, _ := repo.FindByID(id)
    fmt.Println(obj.Name)  // panic if not found
    
    // GOOD — check error first
    obj, err := repo.FindByID(id)
    if err != nil {
        return fmt.Errorf("find user: %w", err)
    }
    if obj == nil {
        return fmt.Errorf("user %d not found", id)
    }
    fmt.Println(obj.Name)
  3. 03

    step 3

    Initialize struct pointer fields before use

    A struct with pointer fields has them all set to nil by default. Initialize them before accessing.

    type Config struct {
        DB     *DBConfig
        Server *ServerConfig
    }
    
    // BAD — Config{} leaves DB and Server as nil
    cfg := Config{}
    fmt.Println(cfg.DB.Host)  // panic
    
    // GOOD — initialize all pointer fields
    cfg := Config{
        DB:     &DBConfig{Host: "localhost", Port: 5432},
        Server: &ServerConfig{Port: 8080},
    }
  4. 04

    step 4

    Use the value type instead of a pointer where possible

    If you don't need the semantics of nil (optional value), use a value type instead of a pointer. Value types can never be nil.

    // BAD — pointer required no reason
    type Handler struct {
        logger *log.Logger  // can be nil
    }
    
    // GOOD — value type, never nil
    type Handler struct {
        logger log.Logger  // always initialized
    }

How to verify the fix

  • The panic no longer occurs when running the code path.
  • Nil checks are in place for all pointer results from functions that can return nil.
  • Tests cover the nil/not-found case explicitly.

Why runtime error: invalid memory address or nil pointer dereference happens at the runtime level

In Go, a nil pointer is a pointer variable holding the memory address 0x0. When the runtime attempts to read or write memory at address 0, the OS sends a SIGSEGV signal. The Go runtime catches this signal and converts it into a panic with the message 'invalid memory address or nil pointer dereference'. The panic includes the full goroutine stack which is the primary debugging artifact. Unlike Java's NullPointerException, Go does not give a field name — you must read the stack trace line to identify which dereference caused it.

Common debug mistakes for runtime error: invalid memory address or nil pointer dereference

  • Using `obj, _ := fn()` to ignore errors — the result is nil when the error would have explained why.
  • Returning a typed nil interface (`return (*MyError)(nil)`) instead of a plain `nil` — causes 'nil but not nil' interface comparison bugs.
  • Accessing a map value as a struct pointer without checking if the key exists — unset map keys return the zero value (nil for pointer types).
  • Calling methods on an uninitialized struct embedded pointer — `type A struct { *B }; a := A{}; a.B.Method()` panics.
  • Race condition where one goroutine sets a pointer to nil while another reads it — use sync.Mutex or sync/atomic.

When runtime error: invalid memory address or nil pointer dereference signals a deeper problem

Widespread nil pointer panics in a Go codebase usually indicate that error handling is treated as optional. Go's multi-return idiom `(T, error)` makes nil values almost always paired with an error — if you check the error, you rarely dereference a nil. A codebase with frequent nil panics has systematic error-ignoring, often introduced under time pressure with `_ = err` or by wrapping functions that should return errors into ones that return only the value. Linters like `errcheck` and `revive` with the `unused-parameter` rule catch this pattern statically. Adding them to CI is the architectural fix.

Editor's take

The nil pointer dereference is Go's equivalent of JavaScript's 'Cannot read properties of undefined'. The root cause is almost always the same: a function that can return nil returned nil, the caller didn't check, and the nil propagated a few call frames before panicking somewhere unrelated to the actual problem. The stack trace points at the dereference, not the nil origin.

The production scenario where this is most expensive: a Go API server without a top-level `recover()` in the HTTP handler. A single panicking goroutine kills the entire process. If you're running on Kubernetes, the pod restarts and the error is in the previous pod's logs — which may have already been rotated. Crash loops lose their error context fast. The fix: wrap every HTTP handler in a recovery middleware that catches panics, logs them with `debug.Stack()`, and returns 500. This is a one-time setup that pays dividends every time a nil dereference would otherwise have taken down the server.

The Go-specific pattern that generates the most confusing nil panics: interface nil vs typed nil. When a function signature returns `error` but the implementation returns a concrete `*AppError` type, and the error case sets `var err *AppError = nil` then `return err`, the caller's `if err != nil` passes (because the interface has a non-nil type component), but any attempt to use the error value panics. This is one of the most discussed footguns in the Go community and is the reason the FAQ explicitly warns against returning concrete error types as interface values.

By Bikram Nath · Curator · Updated June 2026

Frequently asked questions

How is a nil interface different from a nil pointer in Go?

An interface value is nil only when both its type and value are nil. A common trap: a function returns `*MyError` (a concrete pointer type) as an `error` interface. Even if the pointer is nil, the interface value is NOT nil — it has a type (`*MyError`) but a nil value. Calling `if err != nil` returns true, but dereferencing inside the error handler panics. Fix: return `nil` directly for the interface type, never a typed nil pointer.

Should I use recover() to catch nil pointer panics?

Rarely. `recover()` is designed for library code that must never crash the caller, not for routine nil-pointer bugs. Fixing nil checks is always better. The exception: a server's top-level HTTP handler should `recover()` from panics, log them, and return a 500 — preventing one bad request from crashing the whole process. Don't use `recover()` as a substitute for fixing the nil check.

Does Go 1.18+ generics change how nil pointers work?

No. Generic type parameters constrained to pointer types can still be nil. A generic function operating on `*T` must still nil-check before dereferencing. The constraint `~*T` or pointer receiver types in generics don't add automatic nil safety.

disclosure:Errordex runs AdSense, has zero third-party affiliate or sponsored links, and occasionally links to the editor’s own paid digital products (clearly labelled). Every fix is cross-referenced against the official sources listed in the “sources” sidebar before it ships. If a fix here didn’t work for you, please email so we can update the page.