go runtime_error ai_generated true

panic: sync: WaitGroup is reused before previous Wait has returned

ID: go/waitgroup-wait-reused-before-return

Also available as: JSON · Markdown · 中文
80%Fix Rate
88%Confidence
0Evidence
2024-04-18First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
1.20 active — — —
1.21 active — — —
1.22 active — — —

Root Cause

Add() is called on a WaitGroup while another goroutine is still blocked in Wait(), which the runtime forbids to prevent counter races.

generic

中文

在另一个 goroutine 仍阻塞在 Wait() 时调用了 Add(),运行时会禁止此操作以防止计数器竞争。

Workarounds

  1. 95% success
    var wg sync.WaitGroup
    for i := 0; i < n; i++ { wg.Add(1) }
    for i := 0; i < n; i++ {
        go func() { defer wg.Done(); work() }()
    }
    wg.Wait()
  2. 93% success
    sem := make(chan struct{}, 10)
    var wg sync.WaitGroup
    for _, job := range jobs {
        sem <- struct{}{}
        wg.Add(1)
        go func(j Job) {
            defer wg.Done()
            defer func() { <-sem }()
            run(j)
        }(job)
    }
    wg.Wait()

Dead Ends

Common approaches that don't work:

  1. 80% fail

    Wait() may return before the goroutine even starts, so Add happens after Wait and the counter update races.

  2. 70% fail

    Sleep does not synchronize Add with Wait; under load the panic still occurs.