multierr

package module
v1.6.0 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2020 License: MIT Imports: 7 Imported by: 4,116

README

multierr GoDoc Build Status Coverage Status

multierr allows combining one or more Go errors together.

Installation

go get -u go.uber.org/multierr

Status

Stable: No breaking changes will be made before 2.0.


Released under the MIT License.

Documentation

Overview

Package multierr allows combining one or more errors together.

Overview

Errors can be combined with the use of the Combine function.

multierr.Combine(
	reader.Close(),
	writer.Close(),
	conn.Close(),
)

If only two errors are being combined, the Append function may be used instead.

err = multierr.Append(reader.Close(), writer.Close())

This makes it possible to record resource cleanup failures from deferred blocks with the help of named return values.

func sendRequest(req Request) (err error) {
	conn, err := openConnection()
	if err != nil {
		return err
	}
	defer func() {
		err = multierr.Append(err, conn.Close())
	}()
	// ...
}

The underlying list of errors for a returned error object may be retrieved with the Errors function.

errors := multierr.Errors(err)
if len(errors) > 0 {
	fmt.Println("The following errors occurred:", errors)
}

Advanced Usage

Errors returned by Combine and Append MAY implement the following interface.

type errorGroup interface {
	// Returns a slice containing the underlying list of errors.
	//
	// This slice MUST NOT be modified by the caller.
	Errors() []error
}

Note that if you need access to list of errors behind a multierr error, you should prefer using the Errors function. That said, if you need cheap read-only access to the underlying errors slice, you can attempt to cast the error to this interface. You MUST handle the failure case gracefully because errors returned by Combine and Append are not guaranteed to implement this interface.

var errors []error
group, ok := err.(errorGroup)
if ok {
	errors = group.Errors()
} else {
	errors = []error{err}
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Append

func Append(left error, right error) error

Append appends the given errors together. Either value may be nil.

This function is a specialization of Combine for the common case where there are only two errors.

err = multierr.Append(reader.Close(), writer.Close())

The following pattern may also be used to record failure of deferred operations without losing information about the original error.

func doSomething(..) (err error) {
	f := acquireResource()
	defer func() {
		err = multierr.Append(err, f.Close())
	}()
Example
package main

import (
	"errors"
	"fmt"

	"go.uber.org/multierr"
)

func main() {
	var err error
	err = multierr.Append(err, errors.New("call 1 failed"))
	err = multierr.Append(err, errors.New("call 2 failed"))
	fmt.Println(err)
}
Output:

call 1 failed; call 2 failed

func AppendInto added in v1.4.0

func AppendInto(into *error, err error) (errored bool)

AppendInto appends an error into the destination of an error pointer and returns whether the error being appended was non-nil.

var err error
multierr.AppendInto(&err, r.Close())
multierr.AppendInto(&err, w.Close())

The above is equivalent to,

err := multierr.Append(r.Close(), w.Close())

As AppendInto reports whether the provided error was non-nil, it may be used to build a multierr error in a loop more ergonomically. For example:

var err error
for line := range lines {
	var item Item
	if multierr.AppendInto(&err, parse(line, &item)) {
		continue
	}
	items = append(items, item)
}

Compare this with a verison that relies solely on Append:

var err error
for line := range lines {
	var item Item
	if parseErr := parse(line, &item); parseErr != nil {
		err = multierr.Append(err, parseErr)
		continue
	}
	items = append(items, item)
}
Example
package main

import (
	"errors"
	"fmt"

	"go.uber.org/multierr"
)

func main() {
	var err error

	if multierr.AppendInto(&err, errors.New("foo")) {
		fmt.Println("call 1 failed")
	}

	if multierr.AppendInto(&err, nil) {
		fmt.Println("call 2 failed")
	}

	if multierr.AppendInto(&err, errors.New("baz")) {
		fmt.Println("call 3 failed")
	}

	fmt.Println(err)
}
Output:

call 1 failed
call 3 failed
foo; baz

func Combine

func Combine(errors ...error) error

Combine combines the passed errors into a single error.

If zero arguments were passed or if all items are nil, a nil error is returned.

Combine(nil, nil)  // == nil

If only a single error was passed, it is returned as-is.

Combine(err)  // == err

Combine skips over nil arguments so this function may be used to combine together errors from operations that fail independently of each other.

multierr.Combine(
	reader.Close(),
	writer.Close(),
	pipe.Close(),
)

If any of the passed errors is a multierr error, it will be flattened along with the other errors.

multierr.Combine(multierr.Combine(err1, err2), err3)
// is the same as
multierr.Combine(err1, err2, err3)

The returned error formats into a readable multi-line error message if formatted with %+v.

fmt.Sprintf("%+v", multierr.Combine(err1, err2))
Example
package main

import (
	"errors"
	"fmt"

	"go.uber.org/multierr"
)

func main() {
	err := multierr.Combine(
		errors.New("call 1 failed"),
		nil, // successful request
		errors.New("call 3 failed"),
		nil, // successful request
		errors.New("call 5 failed"),
	)
	fmt.Printf("%+v", err)
}
Output:

the following errors occurred:
 -  call 1 failed
 -  call 3 failed
 -  call 5 failed

func Errors added in v1.1.0

func Errors(err error) []error

Errors returns a slice containing zero or more errors that the supplied error is composed of. If the error is nil, a nil slice is returned.

err := multierr.Append(r.Close(), w.Close())
errors := multierr.Errors(err)

If the error is not composed of other errors, the returned slice contains just the error that was passed in.

Callers of this function are free to modify the returned slice.

Example
package main

import (
	"errors"
	"fmt"

	"go.uber.org/multierr"
)

func main() {
	err := multierr.Combine(
		nil, // successful request
		errors.New("call 2 failed"),
		errors.New("call 3 failed"),
	)
	err = multierr.Append(err, nil) // successful request
	err = multierr.Append(err, errors.New("call 5 failed"))

	errors := multierr.Errors(err)
	for _, err := range errors {
		fmt.Println(err)
	}
}
Output:

call 2 failed
call 3 failed
call 5 failed

Types

This section is empty.

Jump to

Keyboard shortcuts

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