Goroutine Leak

goroutine leak detected: background goroutines still running after test completion

Quick Answer

A goroutine is blocked forever because nothing will send to or receive from its channel, or its context was never cancelled. Always provide a way for goroutines to exit.

Why This Happens

Goroutine leaks happen when a goroutine blocks indefinitely on a channel operation, mutex lock, or other synchronization primitive and has no way to be cancelled. Over time this causes increasing memory usage and can crash your application. Use context cancellation or done channels to signal goroutines to exit.

The Problem

func process() {
    ch := make(chan int)
    go func() {
        val := <-ch // blocks forever, nothing sends to ch
        fmt.Println(val)
    }()
    // function returns, goroutine leaks
}

The Fix

func process(ctx context.Context) {
    ch := make(chan int)
    go func() {
        select {
        case val := <-ch:
            fmt.Println(val)
        case <-ctx.Done():
            return
        }
    }()
}

Step-by-Step Fix

  1. 1

    Identify the blocked goroutine

    Use runtime.NumGoroutine() or pprof to find goroutines that are stuck and examine their stack traces.

  2. 2

    Find the blocking operation

    Determine which channel operation, mutex, or I/O call is preventing the goroutine from completing.

  3. 3

    Add cancellation support

    Use context.WithCancel or a done channel in a select statement so the goroutine can exit when no longer needed.

Bugsly catches this automatically

Bugsly's AI analyzes this error pattern in real-time, explains what went wrong in plain English, and suggests the exact fix — before your users even report it.

Try Bugsly free