Reliability and safety
concurrentcapture
Checks locals mutated by goroutines launched repeatedly.
What it detects
Goroutines launched from a loop should not mutate the same captured local without synchronization. Prefer returning results through a channel or keeping the value local to each goroutine.
Checks
| Check | What it detects |
|---|---|
shared-capture |
Reports repeatedly launched goroutines that mutate the same captured local. |
Why this is flagged
Those goroutines run at unpredictable times and may read or write the captured value simultaneously. The result is a data race whose output can change from run to run and may only fail under load.
Further reading: Data race detector, The Go memory model.
How to fix it
Keep the changing value local to each goroutine and send the finished result back through a channel. If the value truly must be shared, protect every access with the same synchronization mechanism.
Examples
Flagged code
func collect(items []int) error { var err error for range items { go func() { // gohawk: captured local err is mutated by goroutines launched repeatedly err = fetch() }() } return err}Accepted code
func collectSafely(items []int) error { var group sync.WaitGroup errs := make(chan error, len(items)) for range items { group.Add(1) go func() { defer group.Done() errs <- fetch() }() } group.Wait() close(errs) for err := range errs { if err != nil { return err } } return nil}