a common mistake when using Send Receive Operations
Fast recall
Quick revision
Core answer
Practical understanding of Send Receive Operations.
Repeating a definition without saying when to use it.
Give one trade-off and say how you would test it.
Interview-ready guide
Interview answer
It panics — immediately, on the send:
ch := make(chan int, 1)
close(ch)
ch <- 1 // panic: send on closed channelExecuted and transcribed: the panic text is literally send on closed channel. Not a block, not a silent drop — a hard failure designed to be loud.
Why so harsh: close broadcasts 'no more values coming' to every receiver. A send after close would make that broadcast a lie — receivers that already observed the close and exited would have missed the late value, and the channel's FIFO-then-tombstone contract would be incoherent. Go enforces the invariant with the only mechanism that can't be ignored: the panic.
The design consequence, and the rule to take into code: exactly one owner closes, and that owner is on the SEND side. Multiple senders can't safely close (who knows no one else will send?), which is why multi-sender topologies either use a dedicated closer channel, a sync.WaitGroup before the closer, or a single fan-in goroutine that owns the close. Receivers never close: closing from the receive side races every other receiver's comma-ok — the same one-way-signal logic, mirrored.
The panic-vs-block contrast is the interview-grade point: every other invalid channel state blocks (nil) or degrades gracefully (closed reads). Only the send-after-close panics, because it's the only state that would corrupt the channel's semantic contract rather than just stall it.
a common mistake when using Send Receive Operations
Direct Answer
Panics immediately: send on closed channel. Close is a one-way, sender-owned signal — the channel must never be sent to after close.
Deep Dive & Architecture
The mechanics of why close-then-send panics while close-then-receive degrades: close marks the channel by closing the send-side of the state machine — a flag (closed=1) on the hchan and a wake-up broadcast to ALL parked receivers. Receivers, on waking, find the flag, and each takes either a buffered value or the (zero, false) result. The channel is permanently readable.
The send path checks the same flag first: closed → panic. No waiting, no recovery path — the check is at the top of the send, before any queueing. Because the check is under the channel lock, a send racing a close is decided atomically: either the send enqueued before close (receiver will get it — FIFO preserved) or close won (send panics). There's no interleaving where a value vanishes.
That's the same design philosophy as Go's map-concurrent-access panic: concurrent contract violations should crash LOUDLY in development rather than corrupt quietly in production. A send-after-close is almost always a lifecycle bug — some goroutine didn't get the shutdown signal — and the panic is the stack trace pointing at the goroutine that missed it.
The close protocol in one sentence, worth memorizing because it summarizes the entire ownership model: ONE sender (or an owner coordinating all senders) closes when production is complete; receivers drain via range or comma-ok; nobody sends after; nobody receives-closes. Channels with that discipline compose into pipelines that never hit the panic.
Common Mistakes & Pitfalls
Repeating a definition without saying when to use it.
Check your understanding
Answer these without looking back at the article.
- What is Send Receive Operations, and when would you use it?
- When would you use Send Receive Operations in a real project?
- How would you compare Send Receive Operations with an alternative?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.