How to Use errgroup in Go for Concurrent Error Handling
Use
errgroup.Group to run multiple goroutines concurrently and collect errors. Create a group, start goroutines with Go(func() error), then call Wait() to wait for all to finish and get the first error if any.Syntax
The errgroup package provides a Group type to manage multiple goroutines. You create a group, then use Go(func() error) to start goroutines that return errors. Finally, call Wait() to block until all goroutines finish and get the first error encountered.
var g errgroup.Group: declares a group.g.Go(func() error { ... }): runs a goroutine that returns an error.err := g.Wait(): waits for all goroutines and returns the first error or nil.
go
var g errgroup.Group g.Go(func() error { // your concurrent task return nil }) err := g.Wait() if err != nil { // handle error }
Example
This example shows how to use errgroup to run two tasks concurrently. Each task simulates work and may return an error. The program waits for both to finish and prints the first error if any.
go
package main import ( "errors" "fmt" "golang.org/x/sync/errgroup" "time" ) func main() { var g errgroup.Group // Task 1: succeeds after 1 second g.Go(func() error { time.Sleep(1 * time.Second) fmt.Println("Task 1 done") return nil }) // Task 2: fails after 500 milliseconds g.Go(func() error { time.Sleep(500 * time.Millisecond) fmt.Println("Task 2 done with error") return errors.New("error in task 2") }) // Wait for all tasks err := g.Wait() if err != nil { fmt.Println("Received error:", err) } else { fmt.Println("All tasks completed successfully") } }
Output
Task 2 done with error
Task 1 done
Received error: error in task 2
Common Pitfalls
Common mistakes when using errgroup include:
- Not returning errors from goroutines, which makes
Wait()always return nil. - Starting goroutines outside
g.Go(), losing error tracking. - Ignoring the error returned by
Wait(). - Assuming
Wait()waits for goroutines started outside the group.
Always start goroutines with g.Go() and return errors properly.
go
package main import ( "errors" "fmt" "golang.org/x/sync/errgroup" ) func main() { var g errgroup.Group // Wrong: goroutine started outside errgroup go func() { // This goroutine's error is not tracked by errgroup _ = errors.New("error") }() // Correct: goroutine started with errgroup g.Go(func() error { return errors.New("error") }) err := g.Wait() if err != nil { fmt.Println("Error detected:", err) } }
Output
Error detected: error
Quick Reference
| Function | Description |
|---|---|
| var g errgroup.Group | Create a new errgroup to manage goroutines |
| g.Go(func() error) | Start a goroutine that returns an error |
| g.Wait() error | Wait for all goroutines to finish and return the first error |
| Returns nil | If all goroutines complete without error |
Key Takeaways
Use errgroup.Group to run multiple goroutines and collect errors easily.
Always start goroutines with g.Go to track errors properly.
Call g.Wait() to wait for all goroutines and get the first error returned.
Return errors from your goroutines to enable error detection.
Do not start goroutines outside errgroup if you want error handling.