Skip to content
Latchkey

Go "all goroutines are asleep - deadlock!" in Tests - Fix in CI

The Go runtime detected that every goroutine is blocked with no way to make progress and aborts with a deadlock fatal error. A test is waiting on a channel, WaitGroup, or lock that nothing will ever release.

What this error means

A test crashes with fatal error: all goroutines are asleep - deadlock! and a goroutine dump showing where each is blocked. It is deterministic when the logic is wrong, and the dump points at the blocking operation.

go test output
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
	main_test.go:18 +0x65

Common causes

A receive on a channel no one sends to

A test reads from a channel that is never written (or a sender exited early), so the receive blocks forever.

A WaitGroup or mutex misuse

A WaitGroup with more Wait than Done, or a lock acquired twice without release, leaves goroutines permanently blocked.

How to fix it

Ensure every channel has a sender and a close

Guarantee a send for each receive, and close channels when production is done so ranges terminate.

Go
done := make(chan struct{})
go func() { defer close(done); work() }()
<-done   // unblocks when the goroutine finishes

Balance WaitGroup Add/Done

Call Add before launching goroutines and exactly one Done per goroutine.

Go
var wg sync.WaitGroup
for _, t := range tasks {
	wg.Add(1)
	go func(t Task) { defer wg.Done(); run(t) }(t)
}
wg.Wait()

Bound the wait with a timeout

Use a select with a timeout so a stuck test fails with a clear message instead of deadlocking.

Go
select {
case v := <-ch:
	_ = v
case <-time.After(2 * time.Second):
	t.Fatal("timed out waiting for result")
}

How to prevent it

  • Match every channel receive with a guaranteed send (and close).
  • Keep WaitGroup Add/Done balanced.
  • Use select with a timeout in tests that wait on concurrency.

Frequently asked questions

What causes ""deadlock!""?
A test reads from a channel that is never written (or a sender exited early), so the receive blocks forever.
How do I fix "deadlock!"?
Guarantee a send for each receive, and close channels when production is done so ranges terminate.

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card