Error handling
Treat errors as ordinary values, return them early, and add context without obscuring control flow.
Canonical guidance
- return errors explicitly
- handle errors close to the point where useful action can be taken
- add context when returning upward
- keep success path readable by returning early on errors
Use when
- reviewing application control flow
- designing library APIs
Avoid
- panic for expected failures
- swallowing errors
- deeply nested happy-path code caused by delayed error returns
Preferred pattern
u, err := repo.Fetch(ctx, id)
if err != nil {
return User{}, fmt.Errorf("fetch user %q: %w", id, err)
}
return u, nil
Anti-pattern
u, _ := repo.Fetch(ctx, id)
Explanation: This anti-pattern is tempting in prototypes, but ignored errors destroy observability and push failures into harder-to-debug states.
Why
- explicit error values make failure paths inspectable and composable
- contextual wrapping preserves both machine and human usefulness
Related pages
Sources
- Errors are values - Rob Pike
- Defer, Panic, and Recover - Andrew Gerrand