goroutine leak
Go Programming Language
Severity: ModerateWhat Does This Error Mean?
A goroutine leak happens when a goroutine starts but never exits. Leaked goroutines consume memory and CPU indefinitely. Unlike crashed goroutines, leaks are silent — your program stays running but slowly degrades.
Affected Models
- Go 1.21
- Go 1.22
- Go 1.23
- Go 1.24
Common Causes
- A goroutine blocked waiting on a channel that no one ever sends to or closes
- A goroutine waiting for a context that is never cancelled
- Launching goroutines in a loop without a mechanism to stop them
- A goroutine blocked on a mutex that is never unlocked
- HTTP handlers or background workers that are never shut down gracefully
How to Fix It
-
Use runtime.NumGoroutine() to check how many goroutines are running over time.
Log this number every minute. If it keeps growing without stabilizing, you have a leak.
-
Use pprof to take a goroutine stack dump and see what each goroutine is doing.
Import net/http/pprof and visit /debug/pprof/goroutine?debug=2 to see a full trace of all goroutines.
-
Always pass a context to goroutines and check ctx.Done() inside long-running loops.
select { case <-ctx.Done(): return; case v := <-ch: process(v) } — this lets goroutines exit cleanly.
-
Close channels when you are done sending — goroutines blocked on receive will unblock.
close(ch) unblocks all goroutines waiting on <-ch. Make sure only the sender closes the channel.
-
Use goleak in tests to automatically detect goroutine leaks.
github.com/uber-go/goleak — add goleak.VerifyNone(t) at the end of your tests. It fails if goroutines are still running.
When to Call a Professional
Goroutine leaks in long-running services can accumulate for days before causing an outage. If your service is leaking and you are not sure where, involve a senior developer for profiling. This is a significant production issue that warrants careful investigation.
Frequently Asked Questions
How do I tell if my program has a goroutine leak?
Watch your program's memory usage over time — if it grows steadily, suspect a leak. Also log runtime.NumGoroutine() periodically. A healthy program's goroutine count stays relatively stable.
Do goroutine leaks always crash the program?
No — that is what makes them dangerous. The program keeps running, but performance degrades slowly. Eventually memory is exhausted, or the OS kills the process.
Can goroutines be killed from outside?
No. Go has no way to forcibly terminate a goroutine from outside. The only way to stop a goroutine is from within — using context cancellation or closing a channel. This is why designing for clean shutdown from the start is important.