Involved Source Files 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())
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)
}
# Appending from a loop
You sometimes need to append into an error from a loop.
var err error
for _, item := range items {
err = multierr.Append(err, process(item))
}
Cases like this may require knowledge of whether an individual instance
failed. This usually requires introduction of a new variable.
var err error
for _, item := range items {
if perr := process(item); perr != nil {
log.Warn("skipping item", item)
err = multierr.Append(err, perr)
}
}
multierr includes AppendInto to simplify cases like this.
var err error
for _, item := range items {
if multierr.AppendInto(&err, process(item)) {
log.Warn("skipping item", item)
}
}
This will append the error into the err variable, and return true if that
individual error was non-nil.
See [AppendInto] for more information.
# Deferred Functions
Go makes it possible to modify the return value of a function in a defer
block if the function was using named returns. This makes it possible to
record resource cleanup failures from deferred blocks.
func sendRequest(req Request) (err error) {
conn, err := openConnection()
if err != nil {
return err
}
defer func() {
err = multierr.Append(err, conn.Close())
}()
// ...
}
multierr provides the Invoker type and AppendInvoke function to make cases
like the above simpler and obviate the need for a closure. The following is
roughly equivalent to the example above.
func sendRequest(req Request) (err error) {
conn, err := openConnection()
if err != nil {
return err
}
defer multierr.AppendInvoke(&err, multierr.Close(conn))
// ...
}
See [AppendInvoke] and [Invoker] for more information.
NOTE: If you're modifying an error from inside a defer, you MUST use a named
return value for that function.
# 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}
}error_post_go120.go
Package-Level Type Names (total 6, in which 2 are exported)
/* sort exporteds by: | */
Invoke wraps a function which may fail with an error to match the Invoker
interface. Use it to supply functions matching this signature to
AppendInvoke.
For example,
func processReader(r io.Reader) (err error) {
scanner := bufio.NewScanner(r)
defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
for scanner.Scan() {
// ...
}
// ...
}
In this example, the following line will construct the Invoker right away,
but defer the invocation of scanner.Err() until the function returns.
defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
Note that the error you're appending to from the defer statement MUST be a
named return. Invoke calls the supplied function and returns its result.
Invoke : Invoker
Invoker is an operation that may fail with an error. Use it with
AppendInvoke to append the result of calling the function into an error.
This allows you to conveniently defer capture of failing operations.
See also, [Close] and [Invoke].( Invoker) Invoke() errorInvoke
func Close(closer io.Closer) Invoker
func AppendInvoke(into *error, invoker Invoker)
Total number of errors including multiErrors Whether the list contains at least one multiError Number of top-level non-nil errors Index of the first non-nil error in the list. Value is meaningless if
Count is zero.
func inspect(errors []error) (res inspectResult)
multiError is an error that holds one or more errors.
An instance of this is guaranteed to be non-empty and flattened. That is,
none of the errors inside multiError are other multiErrors.
multiError formats to a semi-colon delimited list of error messages with
%v and with a more readable multi-line format with %+v.copyNeededatomic.Boolerrors[]error(*multiError) Error() string Errors returns the list of underlying errors.
This slice MUST NOT be modified.(*multiError) Format(f fmt.State, c rune) Unwrap returns a list of errors wrapped by this multierr.(*multiError) writeMultiline(w io.Writer)(*multiError) writeSingleline(w io.Writer)
*multiError : error
*multiError : fmt.Formatter
*multiError : errorGroup
*multiError : multipleErrors
*multiError : go.uber.org/zap/zapcore.errorGroup
Package-Level Functions (total 12, in which 8 are exported)
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())
}()
Note that the variable MUST be a named return to append an error to it from
the defer statement. See also [AppendInvoke].
AppendFunc is a shorthand for [AppendInvoke].
It allows using function or method value directly
without having to wrap it into an [Invoker] interface.
func doSomething(...) (err error) {
w, err := startWorker(...)
if err != nil {
return err
}
// multierr will call w.Stop() when this function returns and
// if the operation fails, it appends its error into the
// returned error.
defer multierr.AppendFunc(&err, w.Stop)
}
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 version 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)
}
AppendInvoke appends the result of calling the given Invoker into the
provided error pointer. Use it with named returns to safely defer
invocation of fallible operations until a function returns, and capture the
resulting errors.
func doSomething(...) (err error) {
// ...
f, err := openFile(..)
if err != nil {
return err
}
// multierr will call f.Close() when this function returns and
// if the operation fails, its append its error into the
// returned error.
defer multierr.AppendInvoke(&err, multierr.Close(f))
scanner := bufio.NewScanner(f)
// Similarly, this scheduled scanner.Err to be called and
// inspected when the function returns and append its error
// into the returned error.
defer multierr.AppendInvoke(&err, multierr.Invoke(scanner.Err))
// ...
}
NOTE: If used with a defer, the error variable MUST be a named return.
Without defer, AppendInvoke behaves exactly like AppendInto.
err := // ...
multierr.AppendInvoke(&err, mutltierr.Invoke(foo))
// ...is roughly equivalent to...
err := // ...
multierr.AppendInto(&err, foo())
The advantage of the indirection introduced by Invoker is to make it easy
to defer the invocation of a function. Without this indirection, the
invoked function will be evaluated at the time of the defer block rather
than when the function returns.
// BAD: This is likely not what the caller intended. This will evaluate
// foo() right away and append its result into the error when the
// function returns.
defer multierr.AppendInto(&err, foo())
// GOOD: This will defer invocation of foo unutil the function returns.
defer multierr.AppendInvoke(&err, multierr.Invoke(foo))
multierr provides a few Invoker implementations out of the box for
convenience. See [Invoker] for more information.
Close builds an Invoker that closes the provided io.Closer. Use it with
AppendInvoke to close io.Closers and append their results into an error.
For example,
func processFile(path string) (err error) {
f, err := os.Open(path)
if err != nil {
return err
}
defer multierr.AppendInvoke(&err, multierr.Close(f))
return processReader(f)
}
In this example, multierr.Close will construct the Invoker right away, but
defer the invocation of f.Close until the function returns.
defer multierr.AppendInvoke(&err, multierr.Close(f))
Note that the error you're appending to from the defer statement MUST be a
named return.
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))
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.
Every compares every error in the given err against the given target error
using [errors.Is], and returns true only if every comparison returned true.
Prefix for the first and following lines of an item in a list of
multi-line error messages.
For example, if a single item is:
foo
bar
It will become,
- foo
bar
Separator for single-line error messages.
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.