Collect concurrent errors with Group
When you need to execute multiple independent tasks concurrently and collect any errors they might produce, multierror.Group provides a mechanism to coordinate these operations. Unlike standard concurrency patterns that might only return the first error encountered, this group ensures that every scheduled function completes and every returned error is captured.
Running Successful Tasks
In scenarios where all concurrent functions return nil, the Wait method returns nil. This allows you to use the group result in standard error-checking logic. You use the Go method to schedule work and Wait to block until all scheduled functions have finished execution.
package main
import (
"sync/atomic"
"github.com/hashicorp/go-multierror"
)
func main() {
var group multierror.Group
var ran atomic.Int32
group.Go(func() error { ran.Add(1); return nil })
group.Go(func() error { ran.Add(1); return nil })
result := group.Wait()
if result != nil || ran.Load() != 2 {
panic("expected both functions and no errors")
}
}
Collecting Multiple Errors
If one or more functions return an error, go-multierror captures the failures. The Wait method returns a non-nil error value that represents the collection of all errors returned by the functions. Because the functions run concurrently in separate goroutines, the order in which errors are collected is treated as unspecified.
package main
import (
"errors"
"sync/atomic"
"github.com/hashicorp/go-multierror"
)
func main() {
var group multierror.Group
var ran atomic.Int32
group.Go(func() error { ran.Add(1); return errors.New("alpha") })
group.Go(func() error { ran.Add(1); return errors.New("beta") })
result := group.Wait()
if result == nil || ran.Load() != 2 {
panic("expected both functions and errors")
}
}
Coordination and Execution
The multierror.Group coordinates execution through two primary methods:
Go: This method accepts a function that returns an error. It immediately schedules the function to run in a new goroutine. If the function returns a non-nil error, the group captures it for later retrieval.Wait: This method blocks the calling goroutine until every function passed toGohas returned. Once all functions are finished, it returns a single error value. If no errors occurred, this value isnil; otherwise, it is a non-nil error containing all collected failures.
When using Go inside a loop, ensure that variables used within the function closure are correctly handled to avoid race conditions. The group is designed to aggregate returned errors but does not provide built-in mechanisms for recovering from panics or managing external side effects like timeouts. All synchronization required to collect errors safely across goroutines is handled internally by the group.