go runtime_error ai_generated true

panic: sync: negative WaitGroup counter

ID: go/sync-waitgroup-negative-counter

Also available as: JSON · Markdown · 中文
80%Fix Rate
89%Confidence
0Evidence
2024-02-14First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
1.x active — — —

Root Cause

wg.Done() is called more times than wg.Add(n), often because Done is called in a goroutine that was never added, or Add is called after Wait has already returned.

generic

中文

wg.Done() 调用次数大于 wg.Add(n),常见于在未 Add 的 goroutine 中调用 Done,或 Wait 返回后才调用 Add。

Workarounds

  1. 97% success
    for _, item := range items {
        wg.Add(1)
        go func(it Item) {
            defer wg.Done()
            process(it)
        }(item)
    }
    wg.Wait()
  2. 95% success
    g, ctx := errgroup.WithContext(ctx)
    for _, it := range items {
        it := it
        g.Go(func() error { return process(ctx, it) })
    }
    if err := g.Wait(); err != nil { return err }

Dead Ends

Common approaches that don't work:

  1. 70% fail

    Race with wg.Wait(): Wait may return before Add runs, then Done panics or Wait returns early.

  2. 75% fail

    Hides the bug; the WaitGroup is now inconsistent and Wait may hang or return prematurely.