Go Concurrency Interview: 5 Fatal Close Pitfalls That Crash Programs

The article dissects five common ways misusing the close operation on Go channels can cause runtime panics, explains the underlying reasons, demonstrates correct patterns such as the single‑sender rule and for‑range consumption, and provides interview‑ready takeaways.

Tinker Programmer
Tinker Programmer
Tinker Programmer
Go Concurrency Interview: 5 Fatal Close Pitfalls That Crash Programs

Snippet 1: Sending on a Closed Channel

Example:

ch := make(chan int)
close(ch) // close the channel
ch <- 1 // panic: send on closed channel

Running this produces a panic stack trace because the runtime aborts when data is sent to a closed channel. This bug is hard to catch in small tests but will crash production under concurrency.

Correct practice: Never send to a channel unless you are certain it is still open. If the sender has closed the channel, other senders must stop.

Snippet 2: Closing a Channel Multiple Times

ch := make(chan int, 1)
close(ch)
fmt.Println("first close succeeded")
close(ch) // panic: close of closed channel

The second call to close panics because a channel may be closed only once. In complex concurrent code, multiple goroutines may each think they should close the channel, leading to a panic.

Correct practice: Assign the right to close the channel to a single goroutine; only that goroutine should invoke close.

Snippet 3: Receiving from a Closed Channel

ch := make(chan int, 2)
ch <- 10
ch <- 20
close(ch)

v, ok := <-ch
fmt.Println("receive:", v, "ok:", ok) // 10 true
v, ok = <-ch
fmt.Println("receive:", v, "ok:", ok) // 20 true
v, ok = <-ch
fmt.Println("receive:", v, "ok:", ok) // 0 false

After the buffered values are read, further receives return the zero value and ok == false, indicating the channel is closed and empty. Relying only on the value (e.g., if v == 0 { … }) can misinterpret this as valid data.

Using the two‑value receive ( v, ok := <-ch) or a for range loop avoids this pitfall.

Snippet 4: Reading Remaining Buffered Data After Close

ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)

for v := range ch {
    fmt.Println("received:", v)
}

Closing does not discard buffered data; the loop reads the remaining values (1, 2, 3) and then exits without blocking.

For an unbuffered channel that is closed without any prior send, a receive yields the zero value and ok == false, which is normal behavior.

Snippet 5: Who Should Close? The Single‑Sender Principle

ch := make(chan int, 5)
var wg sync.WaitGroup
wg.Add(1)
go func() {
    defer wg.Done()
    for i := 1; i <= 5; i++ {
        ch <- i
    }
    close(ch) // sender closes ✅
}()

for v := range ch {
    fmt.Println("received:", v)
}
wg.Wait()

The sender closes the channel after all values are sent; the receiver consumes them with a for range loop, which exits cleanly.

If multiple senders each attempt to close the channel, only the first succeeds; the others panic with "close of closed channel".

Key Takeaways for Interview Questions

Rule 1: Sender closes, receiver uses for range (or the two‑value receive) to finish.

Rule 2: Ensure the sender is the only goroutine that may close the channel; otherwise use a separate done signal.

Rule 3: Always read from a closed channel with the two‑value form or for range; the zero value is not an error.

Understanding these patterns prevents runtime panics in production and equips you to answer high‑frequency Go concurrency interview questions.

Series Recap

The four‑part series covered output prediction, alternating prints, worker pools, and finally close semantics. Together they provide a complete methodology for analyzing and writing concurrent Go code.

Immediate Actions

Run the five code snippets locally to see the panic messages and correct behavior.

Search your Go projects for close( calls; verify that each channel follows the single‑sender rule.

Pick a real interview problem involving channel close and solve it using the "sender close, receiver for‑range" principle.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

concurrencygointerviewchannelpanicclose
Tinker Programmer
Written by

Tinker Programmer

Solving problems with code, sharing practical tech insights, and leveling up together!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.