Accumulate and inspect multiple errors
To collect multiple errors from a sequence of operations, you can incrementally append them to an error variable. The go-multierror package simplifies this process by handling the nil case automatically and providing helpers for inspecting the results.
Accumulate Errors and Check for Existence
Start with a nil error variable. Use the multierror.Append function to add errors as they occur. The function returns a new error value that contains all the appended errors. After collecting errors, you can use the ErrorOrNil method to get a nil value if no errors were appended, which is idiomatic for Go error handling.
The following example appends two errors and then confirms that the resulting error value is not nil.
package main
import (
"errors"
"github.com/hashicorp/go-multierror"
)
// errorCollection is an interface to access multierror methods
// without a direct dependency on the concrete type.
type errorCollection interface {
ErrorOrNil() error
}
func main() {
var result error
result = multierror.Append(result, errors.New("first error"))
result = multierror.Append(result, errors.New("second error"))
// Assert to an interface to call the method
ec, ok := result.(errorCollection)
if !ok {
panic("result does not implement errorCollection")
}
// Check if the result contains any errors.
if ec.ErrorOrNil() == nil {
panic("expected an error, but got nil")
}
}
Inspect Individual Wrapped Errors
After accumulating errors, you may need to inspect the individual errors that were collected. The WrappedErrors method returns a slice of the original error values that were appended. This allows you to check the number of errors or to use functions like errors.Is or errors.As on each individual error.
This example collects two distinct errors and then uses WrappedErrors to retrieve and verify the original errors.
package main
import (
"errors"
"github.com/hashicorp/go-multierror"
"reflect"
)
// errorWrapper is an interface to access multierror methods
// without a direct dependency on the concrete type.
type errorWrapper interface {
WrappedErrors() []error
}
func main() {
var result error
err1 := errors.New("first error")
err2 := errors.New("second error")
result = multierror.Append(result, err1)
result = multierror.Append(result, err2)
// Assert to an interface to call the method
ew, ok := result.(errorWrapper)
if !ok {
panic("result does not implement errorWrapper")
}
wrapped := ew.WrappedErrors()
expected := []error{err1, err2}
if !reflect.DeepEqual(wrapped, expected) {
panic("retrieved errors do not match expected errors")
}
}