Go Tutorial · Errors · Lesson 22 of 30
Go Error Handling
error values, wrapping with %w, errors.Is and errors.As, panic and recover.
Errors are values
Functions return an error as their last result; callers check it right away. It's explicit and a little verbose — on purpose:
package main
import (
"fmt"
"strconv"
)
func parsePort(s string) (int, error) {
n, err := strconv.Atoi(s)
if err != nil {
return 0, fmt.Errorf("invalid port %q", s)
}
return n, nil
}
func main() {
for _, input := range []string{"8080", "eighty"} {
port, err := parsePort(input)
if err != nil {
fmt.Println("error:", err)
continue
}
fmt.Println("port", port)
}
}
Output
port 8080 error: invalid port "eighty"
Run this on your computer — see “Get Started” for setup.
Wrapping errors
Add context with fmt.Errorf("...: %w", err). errors.Is checks for a specific error anywhere in the chain; errors.As extracts a custom error type:
package main
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("not found")
func findUser(id int) (string, error) {
return "", fmt.Errorf("find user %d: %w", id, ErrNotFound)
}
type ValidationError struct{ Field string }
func (e *ValidationError) Error() string { return e.Field + " is required" }
func validate(name string) error {
if name == "" {
return fmt.Errorf("create user: %w", &ValidationError{Field: "name"})
}
return nil
}
func main() {
_, err := findUser(42)
fmt.Println(err)
fmt.Println(errors.Is(err, ErrNotFound))
err = validate("")
var ve *ValidationError
if errors.As(err, &ve) {
fmt.Println("invalid field:", ve.Field)
}
}
Output
find user 42: not found true invalid field: name
Run this on your computer — see “Get Started” for setup.
panic and recover
panic is for truly unrecoverable situations (programmer bugs), not normal errors. recover inside a deferred function stops a panic — used at boundaries such as HTTP handlers so one bad request doesn't crash the server:
package main
import "fmt"
func safeRun(f func()) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("recovered: %v", r)
}
}()
f()
return nil
}
func main() {
fmt.Println(safeRun(func() { fmt.Println("all good") }))
fmt.Println(safeRun(func() {
var items []int
_ = items[3] // index out of range: panics
}))
}
Output
all good <nil> recovered: runtime error: index out of range [3] with length 0
Run this on your computer — see “Get Started” for setup.
Test yourself
Which function checks whether an error chain contains a specific error value?
errors.Aserrors.Iserrors.Unwraperr == target
Show answer
Answer: errors.Is