panjf2000/ants · error

this pool has been closed

Error message

this pool has been closed

What it means

ErrPoolClosed is returned when submitting to or releasing a pool that has already been closed. Once p.Release() (or a failed ReleaseContext) has shut the pool down, further Submit/retrieve calls (ants.go:544) and ReleaseContext calls (ants.go:433) fail with this sentinel. It signals a lifecycle misuse: the pool must not be used after termination.

Source

Thrown at ants.go:70

)

const (
	// OPENED represents that the pool is opened.
	OPENED = iota

	// CLOSED represents that the pool is closed.
	CLOSED
)

var (
	// ErrLackPoolFunc will be returned when invokers don't provide function for pool.
	ErrLackPoolFunc = errors.New("must provide function for pool")

	// ErrInvalidPoolExpiry will be returned when setting a negative number as the periodic duration to purge goroutines.
	ErrInvalidPoolExpiry = errors.New("invalid expiry for pool")

	// ErrPoolClosed will be returned when submitting task to a closed pool.
	ErrPoolClosed = errors.New("this pool has been closed")

	// ErrPoolOverload will be returned when the pool is full and no workers available.
	ErrPoolOverload = errors.New("too many goroutines blocked on submit or Nonblocking is set")

	// ErrInvalidPreAllocSize will be returned when trying to set up a negative capacity under PreAlloc mode.
	ErrInvalidPreAllocSize = errors.New("can not set up a negative capacity under PreAlloc mode")

	// ErrTimeout will be returned after the operations timed out.
	ErrTimeout = errors.New("operation timed out")

	// ErrInvalidPoolIndex will be returned when trying to retrieve a pool with an invalid index.
	ErrInvalidPoolIndex = errors.New("invalid pool index")

	// ErrInvalidLoadBalancingStrategy will be returned when trying to create a MultiPool with an invalid load-balancing strategy.
	ErrInvalidLoadBalancingStrategy = errors.New("invalid load-balancing strategy")

	// ErrInvalidMultiPoolSize  will be returned when trying to create a MultiPool with an invalid size.
	ErrInvalidMultiPoolSize = errors.New("invalid size for multiple pool")

View on GitHub (pinned to 107e376781)

Solutions

  1. Check err == ants.ErrPoolClosed after Submit and stop producing (or recreate the pool).
  2. Coordinate shutdown: signal producers to stop (context cancellation / done channel) before calling Release, then Release once.
  3. Guard Release with sync.Once to prevent double-close, and treat closed pool as terminal — do not retry.
  4. If a reboot is intended, create a new pool instance (see TestRebootNewPool).

Example fix

// before
pool.Release()
if err := pool.Submit(task); err != nil {
    return err
}
// after
err := pool.Submit(task)
if errors.Is(err, ants.ErrPoolClosed) {
    return ErrShuttingDown // or recreate pool
}
Defensive patterns

Strategy: try-catch

Try / catch

err := pool.Submit(task)
switch {
case errors.Is(err, ants.ErrPoolClosed):
    return ErrShuttingDown // stop producing; do not retry
case err != nil:
    return err
}

Prevention

When it happens

Trigger: Calling pool.Submit(task) after pool.Release(); calling pool.ReleaseContext(ctx) on an already-closed pool; sharing one pool across goroutines where one goroutine releases it while others still submit.

Common situations: Graceful-shutdown handlers closing the pool while in-flight producers still submit tasks; server reload/restart code paths; accidental double-Release in defer chains.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of panjf2000/ants@107e376781 (2026-09-06). Data as JSON: /api/errors/e0b4ba83d736646f. Report an issue: GitHub.