"Handle an error only once." What does that mean, and what is wrong with log-and-return?
Question 316MediumGo 1.22 to 1.25
Each error should be handled once. Handling means logging it, recovering from it (retry, fallback, default value), or turning it into a response. The alternative is to return it, usually wrapped with context. If you log and also return, every layer logs the same failure, the logs fill with duplicates that have partial context, and it becomes hard to find the real cause.
// Bad: logged here, and again by every caller
func loadUser(id int) (*User, error) {
u, err := db.Get(id)
if err != nil {
log.Printf("db get failed: %v", err)
return nil, err
}
return u, nil
}
// Good: add context, let the top level decide
func loadUser(id int) (*User, error) {
u, err := db.Get(id)
if err != nil {
return nil, fmt.Errorf("load user %d: %w", id, err)
}
return u, nil
}
// Top level (handler/main) handles it exactly once
if err != nil {
slog.Error("request failed", "err", err, "path", r.URL.Path)
http.Error(w, "internal error", http.StatusInternalServerError)
}
Deliberately ignoring an error is also a form of handling. Write _ = f.Close() with a comment so the choice is visible, rather than dropping the error silently.
More on Error Handling & panics
- Q314How do you collect all errors from concurrent workers rather than just the first?
- Q315Go errors don't carry stack traces. How do you get stack information when you need it?
- Q317Why is
defer f.Close()potentially a bug when writing files? How do you handle theCloseerror? - Q318What does this print? (Shadowed
err) - Q319What does
fmt.Errorf("op: %w", err)return whenerris nil? Why does this matter in helper functions? - Q320Explain context errors:
context.Canceled,DeadlineExceeded, andcontext.Cause.