The fatal error: all goroutines are asleep – deadlock! error occurs in Go when “all goroutines in your program are blocked, and none can proceed“.
This can happen for several reasons, such as:
- A goroutine is waiting for a channel to receive data, but there is no other goroutine sending data to that channel.
- A goroutine is waiting for a lock to be acquired, but another goroutine is holding the lock.
- A goroutine is waiting for a condition to be met, but the condition is never met.
A deadlock occurs when two or more goroutines are waiting for each other to finish, and none of them can proceed. This can happen when using channels and sync.Mutex or sync.WaitGroup in a way that causes circular dependencies.
Here’s an example of a deadlock situation.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
wg := new(sync.WaitGroup)
messages := make(chan string)
for x := 1; x <= 4; x++ {
wg.Add(1)
go messageReceiever(x, wg, &messages)
}
for msg := range messages {
fmt.Println(msg)
}
wg.Wait()
close(messages)
}
func messageReceiever(count int, wg *sync.WaitGroup, messages *chan string) {
defer wg.Done()
time.Sleep(time.Millisecond * time.Duration(1000))
*messages <- fmt.Sprintf("John Wick: %d", count)
}
Output
John Wick: 1
John Wick: 4
John Wick: 2
John Wick: 3
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
The issue in the above code is that we used a for loop with range to read from the messages channel, but we didn’t close the channel until after the loop. This causes the loop to wait indefinitely for more messages, creating a deadlock.
To fix the fatal error: all goroutines are asleep – deadlock, you can move the “wg.Wait()” before the for loop and use a “separate goroutine” to close the messages channel after all other goroutines are done.
Here’s the fixed code.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
wg := new(sync.WaitGroup)
messages := make(chan string)
// Start messageReceiever goroutines
for x := 1; x <= 4; x++ {
wg.Add(1)
go messageReceiever(x, wg, messages)
}
// Use a separate goroutine to close the messages channel
go func() {
wg.Wait()
close(messages)
}()
// Read from the messages channel
for msg := range messages {
fmt.Println(msg)
}
}
func messageReceiever(count int, wg *sync.WaitGroup, messages chan string) {
defer wg.Done()
time.Sleep(time.Millisecond * time.Duration(1000))
messages <- fmt.Sprintf("John Wick: %d", count)
}
Output
John Wick: 3
John Wick: 4
John Wick: 1
John Wick: 2
In this fixed version, we created a new goroutine that waits for the other goroutines to finish using wg.Wait(), then closes the messages channel. The for loop with range will now exit once the messages channel is closed, avoiding the deadlock.
The above code creates 4 messageReceiever goroutines that send messages to the messages channel.
The main() function reads messages from the channel and prints them.
The separate goroutine waits for all messageReceiever goroutines to finish and then closes the messages channel.
Here are some tips for avoiding deadlocks in Go:
- Use channels to communicate between goroutines.
- Use locks to protect shared resources.
- Use conditions to wait for events to occur.
- Use the sync package to help you manage goroutines and shared resources.
That’s all!

Krunal Lathiya is a Software Engineer with over eight years of experience. He has developed a strong foundation in computer science principles and a passion for problem-solving. In addition, Krunal has excellent knowledge of Distributed and cloud computing and is an expert in Go Language.