Go error handling patterns that scale: wrapping, unwrapping, sentinels
Go's error handling gets a lot of criticism from developers coming from exception-based languages. But the real problem isn't if err != nil — it's the patterns that get built on top of it. Most tutorials show you bare error returns and call it a day. In a production codebase, you end up with errors that tell you something failed but not where, why, or what caller context led there . The Problem…
Go error handling is often criticized by developers from exception-based languages. However, the issue isn't whether err != nil, but rather the patterns that develop around it. Most tutorials demonstrate bare error returns, yet in production codebases, errors lack context on where, why, or the caller context leading to the failure.
Wrapping errors with fmt.Errorf and %w, introduced in Go 1.13, preserves the original error for later inspection while attaching context at each layer. For instance, getUser(id=%s): sql: no rows in result set indicates the origin and error details. Wrapping at the point of origin, not mid-process, is recommended. However, each wrap adds noise unless new information is provided.
Sentinel errors, package-level variables for comparing against, are useful when callers need to branch based on error types, such as not found or permission denied situations. Yet, they aren't necessary for every internal error. Custom error types can carry structured data like HTTP status codes or failed validation field names, enhancing error handling precision.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.