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
Track up to 100 issues per month on the free plan; events are not billed.
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 moreFrom the same team
SEOBolt
Technical SEO and AI search audits with ready-to-apply fix plans.
Try SEOBolt →GrowFast
Domain in, qualified B2B leads out, with cold outreach and deliverability handled.
Try GrowFast →AutoShort
Turn a topic into a faceless short: AI script, voiceover and captions.
Try AutoShort →RemixViral
Paste a long video and get back the moments worth posting, cut vertical and captioned.
Try RemixViral →