Skip to content
AgileLogics
6 min read

Debugging Basics

Prerequisites: Comments & gofmt

Go problems come in two kinds: compile errors, which stop the program from building, and runtime panics, which crash a program that built successfully.

Reading compile errors

Every compile error names the file, line, and column:

# example.com/hello
./main.go:6:5: declared and not used: x
./main.go:9:5: append(nums, 2) (value of type []int) is not used

main.go:6:5 means line 6, column 5. Fix the first error first — later ones are sometimes caused by it. Go's compiler is strict (unused variables and imports are errors), but its messages are usually direct about what's wrong.

Printf debugging

The quickest way to see what a program is doing is to print values at key points. %+v shows struct field names, %T shows the type, and %q makes empty or whitespace-only strings visible:

package main

import "fmt"

type Order struct {
    ID    int
    Total float64
}

func main() {
    order := Order{ID: 7, Total: 42.5}
    name := " "
    fmt.Printf("DEBUG order=%+v type=%T name=%q\n", order, order, name)
}
DEBUG order={ID:7 Total:42.5} type=main.Order name=" "

Remove these lines once the bug is fixed.

Panics and stack traces

A panic is Go's runtime crash — caused by things like indexing past the end of a slice, dereferencing a nil pointer, or writing to a nil map. Go prints the reason and a stack trace:

panic: runtime error: index out of range [5] with length 3

goroutine 1 [running]:
main.main()
    /home/you/hello/main.go:8 +0x1d
exit status 2

Read it top-down: the first line says what went wrong, and the first line under goroutine 1 that points into your code (main.go:8) says where. In longer traces, skip frames from the standard library until you reach one of your own files.

Using a debugger: Delve

Delve (dlv) is the standard Go debugger. The VS Code Go extension uses it behind the scenes, so you can usually just click in the margin to set a breakpoint and press F5. From a terminal:

go install github.com/go-delve/delve/cmd/dlv@latest
dlv debug          # build and start the program under the debugger
(dlv) break main.go:8
(dlv) continue
(dlv) print nums
(dlv) next
(dlv) quit

Common mistakes

  • Reading only the last line of a long error output — the useful information is usually at the top.
  • Leaving debug Printf calls in finished code.
  • Treating a panic as random: it always points to a specific line and a specific reason.

Practice

This program panics. Find the bug from the panic message and fix it so it prints the sum 60.

package main

import "fmt"

func main() {
    nums := []int{10, 20, 30}
    total := 0
    for i := 0; i <= len(nums); i++ {
        total += nums[i]
    }
    fmt.Println(total)
}
Show solution

The panic says index out of range [3] with length 3: the loop runs while i <= len(nums), so it tries nums[3], one past the last valid index. Use < — or, better, range:

package main

import "fmt"

func main() {
    nums := []int{10, 20, 30}
    total := 0
    for _, n := range nums {
        total += n
    }
    fmt.Println(total) // 60
}