multierr

repository·master·Indexed 22 days ago

https://github.com/uber-go/multierr

A Go library for combining multiple errors into a single error value. It is optimized for performance, compatible with standard library error functions like errors.Is and errors.As, and provides utilities such as Combine, Append, AppendInto, and specialized functions for capturing errors in defer blocks like AppendFunc and AppendInvoke.

Tokens
1.2K
Snippets
6
Records
9
Agent score
29%

What's inside multierr

  1. Overview of multierr features

    master

    multierr is a library for combining one or more Go errors into a single error value.

    Key characteristics include:

    • Idiomatic: It hides underlying error types so you can work exclusively with error values, and provides safe APIs for appending errors within defer statements.
    • Performant: Optimized to avoid allocations and uses slice resizing semantics for efficient appending (e.g., inside loops).
    • Interoperable: Fully compatible with Go standard library error functions like errors.Is and errors.As.
    • Lightweight: Minimal dependencies.
  2. How multierr handles error unwrapping

    master

    Errors returned by Combine and Append may implement the Unwrap() []error method, satisfying the Go 1.20 multi-error interface.

    While you can attempt to type-assert to an interface containing Unwrap() []error for high-performance read-only access, the recommended and safest way to retrieve the underlying errors is via multierr.Errors(err).

  3. Capture deferred errors using AppendInvoke() and AppendFunc()

    master

    To safely capture errors from deferred cleanup operations (like Close()) without losing the function's primary error, use AppendInvoke or AppendFunc.

    CRITICAL: You MUST use a named return value for the function where you are appending the error in a defer block.

    • AppendFunc(into *error, fn func() error): Use this for simple function values.
    • AppendInvoke(into *error, invoker Invoker): Use this with an Invoker (like those created by multierr.Invoke or multierr.Close) to defer the actual execution of the function until the defer block runs.
    // Using AppendFunc for a method value
    func doSomething(...) (err error) {
    	w, err := startWorker(...)
    	if err != nil {
    		return err
    	}
    	defer multierr.AppendFunc(&err, w.Stop)
    	return nil
    }
    
    // Using AppendInvoke with multierr.Close for io.Closers
    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)
    }
  4. Retrieve underlying errors using Errors()

    master

    To access the individual errors contained within a multierr error, use the multierr.Errors(err) function. This returns a slice of errors. If the input error is not a multierr, the slice will contain only that single error.

    errors := multierr.Errors(err)
    if len(errors) > 0 {
    	fmt.Println("The following errors occurred:", errors)
    }
  5. Combine multiple errors into one using Combine()

    master

    Use multierr.Combine to merge an arbitrary number of errors into a single error value. It skips over nil arguments. If all arguments are nil, it returns nil. If any argument is already a multierr error, it will be flattened into the resulting error.

    If the resulting error is formatted with %+v, it produces a readable multi-line error message.

    multierr.Combine(
    	reader.Close(),
    	writer.Close(),
    	conn.Close(),
    )
  6. Compare errors with Every()

    master
    The multierr.Every(err, target) function checks if every individual error within the provided err matches the target error using errors.Is. It returns true only if all underlying errors match the target.
  7. Append errors in a loop using AppendInto()

    master

    When iterating over a collection and collecting errors, multierr.AppendInto provides a more ergonomic way to update an error pointer. It returns a boolean indicating whether the error being appended was non-nil, which is useful for control flow (e.g., continue on error).

    var err error
    for _, item := range items {
    	if multierr.AppendInto(&err, process(item)) {
    		log.Warn("skipping item", item)
    	}
    }
  8. Append two errors using Append()

    master

    Use multierr.Append as a specialized, more efficient version of Combine when you only need to join two error values. It handles nil values gracefully: if one is nil, it returns the other.

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