Error Handling the Go Way

Harry · 14 Sep 2026 · 1 views
Advertisement
Advertisement

Errors are values

Go has no try/catch. A function that can fail returns an error as its last value; nil means success. You check it right where it happens:

f, err := os.Open("data.txt")
if err != nil {
    return err            // handle or pass it up
}
defer f.Close()
// ...use f...

This if err != nil pattern appears everywhere in Go. It is verbose, but it makes every failure path visible – you cannot accidentally ignore an error.

Creating and wrapping errors

// a simple error
return fmt.Errorf("user %d not found", id)

// wrap an error with context (%w keeps the original)
if err != nil {
    return fmt.Errorf("loading config: %w", err)
}

Wrapping with %w adds context while preserving the underlying error, so callers can still inspect it with errors.Is and errors.As.

defer for cleanup

defer schedules a call to run when the surrounding function returns, no matter how. It is Go's answer to finally and guarantees resources are released:

func process() error {
    conn := connect()
    defer conn.Close()   // always runs on return
    // ...
    return nil
}

panic and recover (rarely)

panic is for truly unrecoverable situations (programmer bugs), not ordinary errors. It unwinds the stack and, unless recovered, crashes the program. Idiomatic Go handles expected failures with returned errors and reserves panic for the exceptional.

Key points

  • Errors are returned values; check them with if err != nil.
  • Create errors with fmt.Errorf; wrap with %w to keep context.
  • defer guarantees cleanup runs when a function returns.
  • Reserve panic/recover for truly exceptional, unrecoverable cases.
Share this post:

Comments (0)

Please login or register to comment.