Understanding the Error

A Go panic runtime error crashes your program unexpectedly. The error typically looks like this:

``` panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x483c5d]

goroutine 1 [running]: main.processData(0x0, 0x0) /app/main.go:42 +0x3d main.main() /app/main.go:18 +0x85 ```

The panic message tells you exactly where the crash occurred (file and line number), but understanding why it happened requires deeper investigation.

Common Causes

1. Nil Pointer Dereference

The most frequent cause. You're calling a method or accessing a field on a nil pointer.

Problematic code: ```go type User struct { Name string Email string }

func getUser(id int) *User { // Returns nil when user not found return nil }

func main() { user := getUser(123) fmt.Println(user.Name) // PANIC: user is nil } ```

Fixed code: ``go func main() { user := getUser(123) if user == nil { fmt.Println("User not found") return } fmt.Println(user.Name) }

2. Array/Slice Index Out of Bounds

Accessing an index that doesn't exist triggers a panic.

Problematic code: ``go items := []string{"a", "b", "c"} fmt.Println(items[5]) // PANIC: index out of range

Fixed code: ``go items := []string{"a", "b", "c"} if len(items) > 5 { fmt.Println(items[5]) } else { fmt.Println("Index out of bounds") }

3. Map Access Without Checking

Reading from a map key that doesn't exist returns the zero value, but can lead to issues.

Problematic code: ``go config := map[string]string{} port := config["port"] // port is empty string, might cause issues downstream num, _ := strconv.Atoi(port) // Returns 0, may cause logic errors

Fixed code: ``go config := map[string]string{} port, exists := config["port"] if !exists { port = "8080" // default } num, err := strconv.Atoi(port) if err != nil { log.Fatalf("Invalid port: %v", err) }

Diagnosis Steps

Step 1: Capture the Stack Trace

When a panic occurs in production, ensure you have proper logging:

go
defer func() {
    if r := recover(); r != nil {
        log.Printf("Panic recovered: %v", r)
        debug.PrintStack()
    }
}()

Step 2: Enable Core Dumps (Linux/Unix)

bash
ulimit -c unlimited

Then analyze with delve debugger:

bash
dlv core ./your-app core

Step 3: Add Debugging Output

Insert strategic print statements before the panic location:

go
log.Printf("Variable state before operation: %+v", myVar)
log.Printf("Slice length: %d, accessing index: %d", len(items), index)

Step 4: Use Go Race Detector

Some panics are caused by race conditions:

bash
go run -race main.go

Production Recovery Pattern

Implement graceful recovery in HTTP servers:

go
func recoveryMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        defer func() {
            if err := recover(); err != nil {
                log.Printf("Panic recovered in %s %s: %v", r.Method, r.URL.Path, err)
                debug.PrintStack()
                http.Error(w, "Internal Server Error", http.StatusInternalServerError)
            }
        }()
        next.ServeHTTP(w, r)
    })
}

Apply to your router:

go
r := mux.NewRouter()
r.Use(recoveryMiddleware)

Verification

After applying fixes, verify with:

```bash # Run tests go test -v ./...

# Run with race detector go run -race main.go

# Run benchmarks to catch edge cases go test -bench=. -count=100 ```

Prevention Strategies

  1. 1.Use linters: Install and run static analysis tools
bash
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck ./...
  1. 1.Enable nil checks in CI: Use nilaway from Uber
bash
go install go.uber.org/nilaway/cmd/nilaway@latest
nilaway ./...
  1. 1.Write defensive code: Always check for nil and bounds
go
func safeAccess[T any](slice []T, index int) (T, bool) {
    var zero T
    if index < 0 || index >= len(slice) {
        return zero, false
    }
    return slice[index], true
}