channelsafety: Detect sends on closed channels in GoSkip to content
Blog
Concurrency and synchronization

channelsafety

Checks channel operations for use after close.

Tiercore
Kinddefect

What it detects

Reports sends reachable after the same channel has been closed.

Closes and sends inside helpers count too, including helpers in other packages, so a close in one call is matched to a later send on the same channel. The diagnostic points at the send, with the close as a related location.

The full list of precision boundaries, with the fixtures that pin each one, is in the channelsafety design notes.

Checks

Check Tier Kind What it detects
send-after-close
core defect Reports sends reachable after a channel has been closed.

Why this is flagged

Sending on a closed channel is a run-time panic, not an error a caller can recover from in the normal flow, so a reachable send-after-close is a latent crash. It usually means two parts of the code disagree about which one owns closing the channel.

Further reading: The Go Programming Language Specification: Close.

How to fix it

Move the close after the final send or separate the channel lifetimes.

Examples

Flagged code

func sendAfterClose() {
events := make(chan int)
close(events)
// gohawk: send follows close of channel
events <- 1
}

Accepted code

func deferredCloseAfterSends(values []int) <-chan int {
events := make(chan int)
go func() {
defer close(events)
for _, value := range values {
events <- value
}
}()
return events
}