Skip to content
Latchkey

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

When every goroutine is blocked and none can proceed, the runtime detects a deadlock and aborts. In tests this is usually an unbuffered channel with no receiver, or a lock acquired twice.

What this error means

A test crashes with fatal error: all goroutines are asleep - deadlock! and a goroutine dump showing each blocked on a channel or lock. It means the test set up a wait that nothing satisfies.

go
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
	example.com/app.TestPipeline(...)
		pipeline_test.go:31 +0x...

Common causes

Channel send/receive with no counterpart

An unbuffered channel send or receive has no goroutine on the other side, so it blocks forever.

Lock acquired and never released

A mutex is locked twice on the same goroutine, or unlocked on a path that never runs.

How to fix it

Pair every send with a receiver

  1. Ensure a goroutine is reading the channel the test sends on, or buffer it.
Go
ch := make(chan int, 1)
ch <- 1
v := <-ch

Use defer for unlocks

  1. Unlock via defer so the lock is always released, even on early returns.
Go
mu.Lock()
defer mu.Unlock()

How to prevent it

  • Pair every channel operation with a counterpart or a buffer.
  • Always defer mu.Unlock() right after locking.
  • Add timeouts so a stuck test fails loudly instead of hanging.

Related guides

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