panjf2000/ants · warning
pool %d: %v
Error message
pool %d: %v
What it means
This is a wrapped error produced by MultiPool.ReleaseContext (multipool.go:60): each sub-pool's ReleaseContext runs concurrently, and if any fails, the sub-pool's index and original error are combined as `pool %d: %v` via fmt.Errorf. It tells you which sub-pool of a MultiPool failed during graceful release (e.g. it was already closed or the drain context expired).
Source
Thrown at multipool.go:60
RoundRobin LoadBalancingStrategy = 1 << (iota + 1)
// LeastTasks always selects the pool with the least number of pending tasks.
LeastTasks
)
type contextReleaser interface {
ReleaseContext(ctx context.Context) error
}
func releasePools(ctx context.Context, pools []contextReleaser) error {
errCh := make(chan error, len(pools))
var wg errgroup.Group
for i, pool := range pools {
func(p contextReleaser, idx int) {
wg.Go(func() error {
err := p.ReleaseContext(ctx)
if err != nil {
err = fmt.Errorf("pool %d: %v", idx, err)
}
errCh <- err
return err
})
}(pool, i)
}
_ = wg.Wait()
var errStr strings.Builder
for i := 0; i < len(pools); i++ {
if err := <-errCh; err != nil {
errStr.WriteString(err.Error())
errStr.WriteString(" | ")
}
}
if errStr.Len() == 0 {View on GitHub (pinned to 107e376781)
Solutions
- Parse/inspect the wrapped cause: errors.Is on the returned error against ants.ErrPoolClosed or context.DeadlineExceeded to branch behavior.
- Ensure Release is called exactly once; guard MultiPool shutdown with sync.Once.
- Extend the context deadline (or use ReleaseTimeout with a larger duration) if drains time out.
- Log the pool index from the message to identify the misbehaving sub-pool.
Example fix
// before
if err := mp.ReleaseContext(ctx); err != nil {
return err
}
// after
if err := mp.ReleaseContext(ctx); err != nil {
if errors.Is(err, context.DeadlineExceeded) {
log.Warn("multipool drain timeout (per-pool: %v)", err)
} else if errors.Is(err, ants.ErrPoolClosed) {
log.Debug("some sub-pools already closed")
}
return err
} Defensive patterns
Strategy: try-catch
Try / catch
err := mp.ReleaseContext(ctx)
if err != nil {
switch {
case errors.Is(err, ants.ErrPoolClosed):
// already released; ignore or debug-log
case errors.Is(err, context.DeadlineExceeded):
log.Warn("some sub-pools failed to drain: %v", err)
default:
return err
}
} Prevention
- Release the MultiPool exactly once (sync.Once).
- Give the release context enough time for the slowest sub-pool's tasks.
- Parse the `pool %d:` prefix to locate the failing sub-pool when debugging.
When it happens
Trigger: Calling multiPool.ReleaseContext(ctx) where a sub-pool returns an error from ReleaseContext — typically ErrPoolClosed on an already-released sub-pool, or context.DeadlineExceeded when workers do not drain in time; the error is wrapped per-pool as `pool <i>: <cause>`.
Common situations: Double-shutdown paths releasing a MultiPool twice; tight shutdown deadlines with long-running tasks causing per-pool release timeouts; mixed standalone pools and MultiPools where one was closed earlier.
Related errors
- operation timed out
- invalid pool index
- invalid load-balancing strategy
- invalid size for multiple pool
- must provide function for pool
AI-assisted analysis of panjf2000/ants@107e376781 (2026-09-06).
Data as JSON: /api/errors/be47fc796fa39ef1.
Report an issue: GitHub.