Errors & Generics
Error handling in Go
Section titled “Error handling in Go”Most languages handle failures through exceptions — a special control-flow mechanism that unwinds the call stack until a catch block intercepts the problem. Go takes a radically different approach: errors are ordinary values.
A function that can fail returns two values: the result and an error. The caller receives both and decides what to do. There is no hidden control flow, no stack unwinding, no unchecked exceptions. Every error-producing callsite is visible in the code, which makes programs easier to audit and reason about.
The canonical pattern you will see everywhere in Go:
result, err := doSomething()if err != nil { // handle the failure — return, log, wrap, or recover}// err is nil: safe to use resultnil means success. A non-nil error means something went wrong and result should not be trusted.
The error interface
Section titled “The error interface”Go’s error type is defined as a single-method interface in the standard library:
type error interface { Error() string}Any type that implements Error() string satisfies the error interface. This means you can pass simple string-based errors, richly structured errors, and everything in between — all through the same interface. nil is a valid error value and signals the absence of any error.
What this module covers
Section titled “What this module covers”| Lesson | Topic |
|---|---|
| This page | Philosophy overview and first runnable example |
| Error Values | errors.New, fmt.Errorf, sentinel errors, errors.Is |
| Wrapping & Custom Errors | %w, errors.As, custom error types |
| Panic & Recover | When to panic, recover, deferring cleanup |
| Generics | Type parameters, constraints, ~T, union types |
A first look
Section titled “A first look”Here is a minimal function that returns (string, error), demonstrating the fundamental shape of Go error handling:
package main
import ( "errors" "fmt")
func greet(name string) (string, error) { if name == "" { return "", errors.New("name must not be empty") } return fmt.Sprintf("Hello, %s!", name), nil}
func main() { msg, err := greet("Gopher") if err != nil { fmt.Println("error:", err) return } fmt.Println(msg) // Hello, Gopher!
_, err = greet("") if err != nil { fmt.Println("error:", err) // error: name must not be empty }}errors.New creates a simple error value from a static string. The function returns nil as the error on the happy path and a non-nil error on the failure path. The caller checks if err != nil immediately after the call — this is the idiom you will write hundreds of times in Go.