Original post

One of the many benefits of using Go is it’s simplicity when it comes to concurrency. With WaitGroups being an excellent example of this. It can be tricky though to handle both concurrency and errors effectively. This post aims to outline how you can run multiple goroutines and handle any errors effectively, without stopping program execution.

The essence of this comes down to these three key parts:

  • Creating two channels, for passing errors and when the WaitGroup is complete.
  • A final goroutine to listen for the WaitGroup to complete, closing a channel when that happens.
  • A select listening for errors or the WaitGroup to complete, whichever occurs first.
package main

import (

func main() {

        // Make channels to pass fatal errors in WaitGroup
      fatalErrors := make(chan error)
        wgDone := make(chan bool)

        var wg sync.WaitGroup

        go func() {
                log.Println("Waitgroup 1")
                // Do Something...
        go func() {
                log.Println("Waitgroup 2")
                // Example function which returns an error
              err := ReturnsError()
                if err != nil {
                        fatalErrors <- err

        // Important final goroutine to wait until WaitGroup is done
      go func() {

        // Wait until either WaitGroup is done or an error is received through the channel
      select {
        case <-wgDone:
                // carry on
        case err := <-fatalErrors:
                log.Fatal("Error: ", err)

        log.Println("Program executed successfully")

func ReturnsError() error {
        return errors.New("Example error on golangcode.com")

handling errors in wait groups