Skip to content
Ownership and lifecycle

channelpolicy

Checks channel capacity and closing ownership.

Fix offeredNo

What it detects

Reports channels with large constant capacities that have no nearby rationale, code that closes a channel received from its caller, and sends that can happen after the channel has been closed.

Checks

Check What it detects
capacity-rationale*
Reports large constant channel capacities without a nearby bounded rationale.
caller-close
Reports functions that close channels received from their callers.
send-after-close
Reports sends reachable after a channel has been closed.

* Opt-in; requires explicit selection.

Why this is flagged

Closing a channel from the wrong place can race with a sender and panic. Giving one owner responsibility for closing makes the channel’s lifetime predictable; avoiding unexplained large buffers also keeps backpressure problems visible.

Further reading: Go concurrency patterns: Pipelines and cancellation.

How to fix it

Let the code that creates and sends on the channel close it after the last send. Prefer an unbuffered or small channel unless the larger capacity has a clear, documented reason.

Examples

Flagged code

func consume(events chan Event) {
// gohawk: do not close a channel received from caller
defer close(events)
for event := range events {
handle(event)
}
}

Accepted code

func consumeSafely(events <-chan Event) {
for event := range events {
handle(event)
}
}

Options

Knob Default Effect
max-unexplained-capacity 1 Largest channel capacity allowed without a rationale; negative disables the check.