Best practices for error handling in Go.
1// 1. Don't ignore errors2// Bad:3result, _ := doSomething()45// Good:6result, err := doSomething()7if err != nil {8 return fmt.Errorf("doSomething: %w", err)9}1011// 2. Wrap errors with context12func ProcessUser(id int) error {13 user, err := GetUser(id)14 if err != nil {15 return fmt.Errorf("ProcessUser: GetUser(%d): %w", id, err)16 }17 return nil18}1920// 3. Use sentinel errors for checking21var ErrNotFound = errors.New("not found")2223if errors.Is(err, ErrNotFound) {24 http.Error(w, "Not found", 404)25}2627// 4. Custom errors for additional information28type ValidationError struct {29 Field string30 Message string31}3233func (e *ValidationError) Error() string {34 return fmt.Sprintf("%s: %s", e.Field, e.Message)35}3637// 5. Error joining (Go 1.20+)38errs := errors.Join(err1, err2, err3)39if errs != nil {40 log.Println("Multiple errors:", errs)41}4243// 6. errorlint for checking44// Don't use: err == SomeError45// Use: errors.Is(err, SomeError)4647// 7. errgroup for parallel operations48g, ctx := errgroup.WithContext(context.Background())49for _, url := range urls {50 url := url51 g.Go(func() error {52 return fetch(ctx, url)53 })54}55if err := g.Wait(); err != nil {56 return fmt.Errorf("fetch all: %w", err)57}
Golden rules: