Package errors is an errors wrapping package to help propagate and chain errors as well as attach stack traces, tags(additional information) and even a Type classification system to categorize errors into types eg. Permanent vs Transient.
It is a drop in replacement for the std Go errors package. It is also 100% compatible with the Is, As and Unwrap interfaces used within the std library and can be mixed with the built-in error wrapping.
Common Questions
Why another package? There are two main reasons.
-
I think that the programs generating the original error(s) should be responsible for adding internal metadata and details to them. Ultimately developers are concerned with:
- If the error is Transient or Permanent for retries.
- Additional details for logging.
-
IMO most of the existing packages either don't take the error handling far enough, too far or down right unfriendly to use/consume.
- works with go-playground/log, the Tags will be added as Field Key Values and Types will be concatenated as well when using
WithError
- helpers to extract and classify error types using
RegisterHelper(...)
, many already existing such as ioerrors, neterrors, awserrors... - built in helpers only need to be imported, eg.
_ github.com/go-playground/errors/v5/helpers/neterrors
allowing libraries to register their own helpers not needing the caller to do or guess what needs to be imported.
Use go get.
go get -u github.com/go-playground/errors/v5
package main
import (
"fmt"
"io"
"github.com/go-playground/errors/v5"
)
func main() {
err := level1("testing error")
fmt.Println(err)
if errors.HasType(err, "Permanent") {
// os.Exit(1)
fmt.Println("it is a permanent error")
}
// root error
cause := errors.Cause(err)
fmt.Println("CAUSE:", cause)
// can even still inspect the internal error
fmt.Println(errors.Cause(err) == io.EOF) // will extract the cause for you
fmt.Println(errors.Cause(cause) == io.EOF)
// and still in a switch
switch errors.Cause(err) {
case io.EOF:
fmt.Println("EOF error")
default:
fmt.Println("unknown error")
}
}
func level1(value string) error {
if err := level2(value); err != nil {
return errors.Wrap(err, "level2 call failed")
}
return nil
}
func level2(value string) error {
err := io.EOF
return errors.Wrap(err, "failed to do something").AddTypes("Permanent").AddTags(errors.T("value", value))
}
Using Go modules and proper semantic version releases (as always).
Distributed under MIT License, please see license file in code for more details.