Go Error Handling Patterns for Production Code
Go's explicit error handling is a strength when done right. Here are patterns that scale.
Wrap Errors with Context
Always add context when propagating errors:
func GetUser(id string) (*User, error) {
user, err := db.QueryUser(id)
if err != nil {
return nil, fmt.Errorf("get user %s: %w", id, err)
}
return user, nil
}The %w verb wraps the original error, preserving the chain for errors.Is() and errors.As() checks.
Define Custom Error Types
type NotFoundError struct {
Resource string
ID string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s %s not found", e.Resource, e.ID)
}
// Usage
func GetOrder(id string) (*Order, error) {
order, err := repo.Find(id)
if err != nil {
return nil, &NotFoundError{Resource: "order", ID: id}
}
return order, nil
}
// Caller checks error type
var notFound *NotFoundError
if errors.As(err, ¬Found) {
http.Error(w, notFound.Error(), http.StatusNotFound)
return
}Sentinel Errors for Known Conditions
var (
ErrNotFound = errors.New("not found")
ErrUnauthorized = errors.New("unauthorized")
ErrConflict = errors.New("conflict")
)
// Check with errors.Is
if errors.Is(err, ErrNotFound) {
w.WriteHeader(http.StatusNotFound)
}Panic Recovery in HTTP Handlers
func RecoveryMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rec := recover(); rec != nil {
log.Error().Interface("panic", rec).
Str("stack", string(debug.Stack())).Msg("panic recovered")
http.Error(w, "Internal server error", 500)
}
}()
next.ServeHTTP(w, r)
})
}Best Practices Summary
- Always handle errors — never use
_for error returns - Wrap with context — use
fmt.Errorfwith%w - Check error types, not strings — use
errors.Isanderrors.As - Log at the top level — don't log and return; do one or the other
- Report to Bugsly — capture panics and unexpected errors in production for immediate visibility into issues your tests didn't catch
Try Bugsly Free
AI-powered error tracking that explains your bugs. Set up in 2 minutes, free forever for small projects.
Get Started FreeRelated Articles
Remix Performance Monitoring Best Practices
Monitor Remix application performance with loader timing, action profiling, streaming metrics, and server-side rendering optimization.
Read morePHP Performance Monitoring Best Practices
Optimize PHP application performance with OPcache tuning, query monitoring, profiling tools, and real-time performance alerting strategies.
Read moreExpress.js Logging Best Practices for Production
Implement structured logging in Express.js with Winston, request correlation IDs, sensitive data filtering, and log level management.
Read moreHow to Catch Broken Releases Before Users Report Them
A practical guide to using error tracking, release tagging, and automated alerts to detect broken deploys within minutes — not after user complaints.
Read more