Package multierror implements a Join
function that combines two or more Go errors.
go get github.com/justindfuller/go-multierror
Joining two errors:
func main() {
err1 := errors.New("my first error")
err2 := errors.New("my second error")
err := multierror.Join(err1, err2)
fmt.Println(err)
// Found 2 errors:
// my first error
// my second error
}
Joining nil errors will result in nil
so that you don't have to do extra nil
checks before joining:
func main() {
err := multierror.Join(nil, nil, nil)
fmt.Println(err)
// <nil>
}
The resulting errors support many common Go interfaces.
- error
- Stringer
- Marshaler
- GoStringer
- GobEncoder
- BinaryMarshaler
- TextMarshaler
func main() {
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")
err := multierror.Join(err1, err2)
b, _ := json.Marshal(err)
fmt.Println(string(b))
// output: "something bad happened, something is broken"
}
They also support common Go error methods.
- errors.Is
- errors.As
- errors.Unwrap
errors.Is:
func main() {
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")
err3 := errors.New("something is REALLY broken")
err := multierror.Join(err1, err2)
err = multierror.Join(err, err3)
fmt.Println(errors.Is(err, err1))
// output: true
}
errors.As:
func main() {
_, err := os.Open("non-existing")
if err == nil {
fmt.Println("No error")
}
err = multierror.Join(err, errSentinelOne)
var pathError *fs.PathError
fmt.Println(errors.As(err, &pathError))
// output: true
}
I've been unhappy with existing go-multierror
implementations.
There are three that I am aware of:
- The standard library errors.Join
- Hashicorp's go-multierror
- Uber's go-multierr
These libraries have the following problems (in no particular order, not all problems apply to all of them):
- They do not implement common interfaces such as Marshaler, so they don't work with JSON output. This applies to other interfaces and encoders as well.
- They all have different interfaces and methods.
- They expose their underlying error type.
- They import third-party dependencies
This go-multierror
solves these problems by:
- Implementing common interfaces (listed above).
- Aligning the interface with the Go standard library.
- Hiding the underlying error type.
- Using only standard library dependencies