Report #102949
[bug\_fix] goroutine leak: WaitGroup counter becomes negative or program hangs waiting for goroutines
Use a \`sync.WaitGroup\` only for known, bounded goroutine sets, call \`wg.Add\` before launching the goroutine \(not inside it\), and call \`wg.Done\` exactly once per goroutine, ideally with \`defer wg.Done\(\)\` at the top of the goroutine. For cancellation, pair the WaitGroup with a \`context.Context\` and ensure the goroutine returns on \`<-ctx.Done\(\)\`.
Journey Context:
A worker pool implementation spawned goroutines in a loop and called \`wg.Add\(1\)\` inside each goroutine. Under heavy load, some goroutines panicked before calling \`wg.Add\`, while the main goroutine reached \`wg.Wait\(\)\` and hung indefinitely. The developer first suspected a deadlock in a channel and added buffered channels, which did not help. Profiling with \`go tool pprof\` showed a growing number of goroutines stuck on \`sync.\(\*WaitGroup\).Wait\`. The root cause was that \`wg.Add\` must be called before the goroutine starts so the WaitGroup count is reliable; moving it before the \`go\` keyword and adding \`defer wg.Done\(\)\` fixed the leak and made shutdown deterministic.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-07-10T04:45:42.107878+00:00— report_created — created