Skip to content
Latchkey

Go "all goroutines are asleep - deadlock" in test - Fix in CI

When every goroutine is blocked with no way to proceed, the Go runtime detects the deadlock and aborts. In a test this usually means an unmatched channel send/receive or a held lock.

What this error means

A run crashes with fatal error: all goroutines are asleep - deadlock! and a goroutine dump. It often shows in CI where ordering differs enough to leave a channel operation unmatched.

go
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
	example.com/app.TestPipeline(...)
	/app/pipe_test.go:19 +0x90

Common causes

Unmatched channel operation

A receive waits for a send that never happens (or vice versa), so the test blocks forever.

Lock never released

A mutex is locked and not unlocked on some path, blocking every goroutine that needs it.

How to fix it

Match every channel operation

  1. Ensure every send has a receiver and every receive a sender; close channels when done.
Go
close(ch)  // signal no more sends
for v := range ch { /* ... */ }

Add a timeout to surface the block

  1. Use select with a timeout so a deadlock fails fast with a clear message instead of hanging.
Go
select {
case v := <-ch:
	_ = v
case <-time.After(time.Second):
	t.Fatal("timed out waiting on ch")
}

How to prevent it

  • Always pair channel sends and receives; close when done.
  • Defer mutex unlocks so they always run.
  • Use select-with-timeout in tests to avoid silent hangs.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →