Go provides 2 native ways to instatiate an error value:
errors.New
that returns a string error value, very useful to create a simple sentinel error value likevar errNotFound = errors.New("record not found")
.fmt.Errorf
that may return an error that wraps another error, and the wrapped error can be asserted against witherrors.Is
, or retrieved witherrors.As
.
While both approaches are fine for simple programs, they lack depth when it comes to large systems because of:
- No contextual information can be attached to the error. While it’s ok for small programs to work with simple string errors, it’s crucial for sophisticated systems to be able to classify errors using contextual data. For example, it’s important to know which error is caused by the failure of a third party API, which error is caused by the network. This will help the system make better informed decisions based on the error, and also enable monitoring of such errors in an Application Performance Monitor tool (e.g. Datadog or New Relic)
- No way to know which part of the error is safe for consumption by an external client. Large systems usually have to communicate with external services via synchronous API call (e.g. REST or gRPC), or asynchronous message queue (e.g. Amazon SQS). It’s hard to know which part in the error chain created by
fmt.Errorf
is ok for external services to consume to prevent internal leakage.
To solve these problems, I wrote an open-source package https://github.com/xamenyap/errors. The package is under MIT license. Please feel free to suggest ideas for improvement.