Skip to content
This repository has been archived by the owner on Dec 24, 2023. It is now read-only.

Combine Errors in Go

License

Notifications You must be signed in to change notification settings

JustinDFuller/go-multierror

Repository files navigation

go-multierror

Go Reference Build Dependencies Go Report Card License GitHub tag (latest by date)

Package multierror implements a Join function that combines two or more Go errors.

go get github.com/justindfuller/go-multierror

Examples

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>
}

Supported Interfaces

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
}

Why?

I've been unhappy with existing go-multierror implementations. There are three that I am aware of:

  1. The standard library errors.Join
  2. Hashicorp's go-multierror
  3. 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