multierror

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 18, 2023 License: GPL-3.0 Imports: 6 Imported by: 0

README

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.

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.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Join added in v0.0.2

func Join(errors ...error) error

Join one or more errors together into a single error. The resulting value is a multiError containing all non-nil errors provided. If the first error is a multiError, the rest of the errors will be appended to the existing multiError. If the first error is not a multiError, a new multiError will be created for it and all the rest of the errors as well.

Example
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")

err := multierror.Join(err1, err2)

fmt.Println(err)
Output:

Found 2 errors:
	something bad happened
	something is broken
Example (BinaryMarshaler)
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")

marshaler, ok := multierror.Join(err1, err2).(encoding.BinaryMarshaler)
if !ok {
	fmt.Println("Not an encoding.TextMarshaler")

	return
}

b, err := marshaler.MarshalBinary()
if err != nil {
	fmt.Printf("Error encoding text: %s\n", err)

	return
}

b, err = json.Marshal(b)
if err != nil {
	fmt.Println(err)

	return
}

fmt.Println(string(b))
Output:

"Cv+BBQEC/4QAAABF/4IAQUAMAD1Gb3VuZCAyIGVycm9yczoKCXNvbWV0aGluZyBiYWQgaGFwcGVuZWQKCXNvbWV0aGluZyBpcyBicm9rZW4K"
Example (ErrorsAs)
_, 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
Example (ErrorsIs)
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
Example (FmtDefault)
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")

err := multierror.Join(err1, err2)

fmt.Printf("%v", err)
Output:

Found 2 errors:
	something bad happened
	something is broken
Example (FmtGoSyntaxRepresentation)
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")

err := multierror.Join(err1, err2)

fmt.Printf("%#v", err)
Output:

[2]error{"something bad happened","something is broken"}
Example (GobEncode)
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")

var builder strings.Builder
if err := gob.NewEncoder(&builder).Encode(multierror.Join(err1, err2)); err != nil {
	fmt.Println(err)

	return
}

b, err := json.Marshal(builder.String())
if err != nil {
	fmt.Println(err)

	return
}

fmt.Println(string(b))
Output:

"\n\ufffd\ufffd\u0005\u0001\u0002\ufffd\ufffd\u0000\u0000\u0000E\ufffd\ufffd\u0000A@\u000c\u0000=Found 2 errors:\n\tsomething bad happened\n\tsomething is broken\n"
Example (JsonMarshal)
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")

b, err := json.Marshal(multierror.Join(err1, err2))
if err != nil {
	fmt.Println(err)

	return
}

fmt.Println(string(b))
Output:

"something bad happened, something is broken"
Example (Nested)
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(err)
Output:

Found 3 errors:
	something bad happened
	something is broken
	something is REALLY broken
Example (Nil)
err := multierror.Join(nil, nil, nil)

fmt.Println(err)
Output:

<nil>
Example (TextMarshaler)
err1 := errors.New("something bad happened")
err2 := errors.New("something is broken")

marshaler, ok := multierror.Join(err1, err2).(encoding.TextMarshaler)
if !ok {
	fmt.Println("Not an encoding.TextMarshaler")

	return
}

b, err := marshaler.MarshalText()
if err != nil {
	fmt.Printf("Error encoding text: %s\n", err)

	return
}

fmt.Println(string(b))
Output:

Found 2 errors:
	something bad happened
	something is broken

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL