errgroup for Concurrent Error Handling
golang.org/x/sync/errgroup in practice
errgroup for Concurrent Error Handling is a free Go Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Problem with goroutines and errors
Launching goroutines with go func() discards return values including errors. You need extra machinery (channels, WaitGroup) to collect them. errgroup simplifies this.
golang.org/x/sync/errgroup
errgroup.Group runs goroutines and collects errors. Wait() blocks until all goroutines finish and returns the first non-nil error.
var g errgroup.Group
g.Go(func() error { return fetchUsers() })
g.Go(func() error { return fetchOrders() })
if err := g.Wait(); err != nil {
log.Fatal(err)
}errgroup.WithContext
WithContext returns a group and a derived context. The context is cancelled when the first goroutine returns an error, stopping remaining work.
g, ctx := errgroup.WithContext(context.Background())
g.Go(func() error { return doWork(ctx) })
g.Go(func() error { return doOtherWork(ctx) })
err := g.Wait()Collecting results alongside errors
errgroup does not collect results, only errors. Capture results in pre-allocated slices accessed by index to avoid synchronisation:
results := make([]Result, len(items))
for i, item := range items {
i, item := i, item
g.Go(func() error {
r, err := process(ctx, item)
if err != nil { return err }
results[i] = r
return nil
})
}
if err := g.Wait(); err != nil { return err }g.SetLimit (Go 1.20+)
g.SetLimit(n) caps the number of goroutines running concurrently — acts as an inline semaphore without a separate channel.
g.SetLimit(10) // at most 10 goroutines at once
for _, item := range items {
g.Go(func() error { return process(item) })
}g.TryGo
g.TryGo(f) starts the goroutine only if the limit (set by SetLimit) allows. Returns false if not started.
Only first error returned
errgroup returns only the first error. If you need all errors, collect them in a mutex-protected slice inside each goroutine.
var mu sync.Mutex
var errs []error
g.Go(func() error {
if err := doWork(); err != nil {
mu.Lock(); errs = append(errs, err); mu.Unlock()
}
return nil
})Difference from sync.WaitGroup
WaitGroup tracks completion; errgroup tracks completion AND collects errors. Prefer errgroup when any goroutine failure should be reported.
Context cancellation propagation
When errgroup.WithContext is used, the derived context's cancellation signals all other goroutines to stop — similar to cancel-on-first-error semantics.
Testing errgroup code
In tests, inject a context with WithTimeout to ensure the group does not run forever if a goroutine hangs.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
g, ctx := errgroup.WithContext(ctx)Semaphore alternative
Before SetLimit (Go < 1.20), use a buffered channel as a semaphore within individual goroutines to achieve the same effect.
Quick Check
What does errgroup.WithContext return that plain errgroup.Group does not?
Recap: errgroup
Key points:
- g.Go(func() error) — launch and collect first error
- g.Wait() — blocks until all done; returns first error
- WithContext — context cancelled on first error
- g.SetLimit(n) — cap concurrent goroutines (Go 1.20+)
Frequently asked questions
Is the “errgroup for Concurrent Error Handling” lesson free?
Yes — the full text of “errgroup for Concurrent Error Handling” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.
What will I learn in “errgroup for Concurrent Error Handling”?
golang.org/x/sync/errgroup in practice You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Go Academy?
No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “errgroup for Concurrent Error Handling” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Go Academy lesson?
Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Pipeline and Stage Patterns
- errgroup for Concurrent Error Handling
- Semaphore Pattern
- Leak Detection and Cancellation