go runtime_error ai_generated true

panic: close of closed channel (in for range)

ID: go/goroutine-for-range-channel-close

Also available as: JSON · Markdown · 中文
80%Fix Rate
85%Confidence
0Evidence
2024-12-08First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
1.20 active
1.21 active

Root Cause

Closing a channel that is being ranged over by another goroutine, causing a panic when the range attempts to read from the closed channel.

generic

中文

关闭正在被另一个协程 range 的通道,导致 range 尝试从已关闭通道读取时引发恐慌。

Workarounds

  1. 100% success Use a separate goroutine to close the channel after all sends are done.
    ch := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            ch <- i
        }
        close(ch)
    }()
    for v := range ch {
        fmt.Println(v)
    }
  2. 95% success Use a sync.WaitGroup to coordinate closure.
    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 10; i++ {
            ch <- i
        }
    }()
    go func() {
        wg.Wait()
        close(ch)
    }()
    for v := range ch {
        fmt.Println(v)
    }

Dead Ends

Common approaches that don't work:

  1. Closing the channel inside the range loop. 80% fail

    Range loop continues until channel is closed, but closing inside causes panic on next iteration.

  2. Using a defer close in the sender goroutine that ranges. 70% fail

    If the sender is also the range receiver, closing inside the loop is problematic.