How to do better Error Handling with Golang

Golang Error Handling Tutorial


  • Errors as uint64 for better performance
  • By convention, 0 is “OK” or “no error”
  • Use the exhaustive linter with switch
  • Use enums to define error cases
  • Implement Stringer on enums for human readable error messages
  • Use generic T ~uint64 to type custom structs to errors

I have been trying to figure out a better Golang error handling pattern. In my previous posts, I alluded to a potential solution, but after some experimentation, it was insufficient. After revisiting and coming back to this topic a few more times, I think I hit on something. The best part is this requires no external dependencies and does not require wholesale conversions to this new pattern.

Defining an Error in Golang

Defining what an error is gets us to the root of the issue. Usually, in Golang, an error is usually a string or a struct containing a string value. But when something fails in a function, sometimes there is no reason to return an entire human-readable string. Returning an integer constant that identifies the error can be just as good.


Why an integer, though? If we examine error, we can see that it is an interface and therefore using it will cause the value to escape to the heap. That means all errors are heap allocations. While golang utilizes garbage collection, too many heap allocations can cause performance issues across your application. Consider a situation where an application runs nominally and suddenly an influx of errors occurs. You would not want a spike in error value allocations to cause an unexpected CPU spike that could potentially ripple through a system. Defining errors  uint64 solves that problem. That will be heap allocation free.

  • Takeaway: Errors as uint64 for better performance

Case study: Golang’s context.Context

Let us take Err() error from context.Context as an example. In the function comments, it essentially states that it returns one of:

  • No error (nil)
  • var Canceled = errors.New(“context canceled”)
  • var DeadlineExceeded error = deadlineExceededError{}

We can already take that description and use it directly in our first new error pattern example.