panjf2000/ants · warning

operation timed out

Error message

operation timed out

What it means

ErrTimeout is returned by pool.ReleaseTimeout when the graceful release does not complete before the given timeout. ReleaseTimeout wraps ReleaseContext with a context deadline; if the context expires with context.DeadlineExceeded, it is converted to this sentinel (ants.go:422). It means in-flight workers had not finished within the budget.

Source

Thrown at ants.go:79

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")

	// workerChanCap determines whether the channel of a worker should be a buffered channel
	// to get the best performance. Inspired by fasthttp at
	// https://github.com/valyala/fasthttp/blob/master/workerpool.go#L139
	workerChanCap = func() int {
		// Use blocking channel if GOMAXPROCS=1.
		// This switches context from sender to receiver immediately,
		// which results in higher performance (under go1.5 at least).
		if runtime.GOMAXPROCS(0) == 1 {

View on GitHub (pinned to 107e376781)

Solutions

  1. Increase the timeout passed to ReleaseTimeout to cover worst-case task duration.
  2. On ErrTimeout, log the incomplete drain and proceed with forced shutdown (or call Release to force close).
  3. Split long tasks into smaller units or support cancellation via task arguments/context so they finish faster.
  4. Stop producers before draining so no new tasks extend the shutdown window.

Example fix

// before
if err := pool.ReleaseTimeout(time.Second); err != nil {
    panic(err)
}
// after
if errors.Is(err, ants.ErrTimeout) {
    log.Warn("pool drain timed out; forcing release")
    pool.Release()
}
Defensive patterns

Strategy: try-catch

Try / catch

err := pool.ReleaseTimeout(30 * time.Second)
if errors.Is(err, ants.ErrTimeout) {
    log.Warn("drain timed out; forcing release")
    pool.Release()
}

Prevention

When it happens

Trigger: pool.ReleaseTimeout(d) where d elapses while long-running tasks still occupy workers, so pending task submission times out.

Common situations: Shutdown sequences with short drain windows while tasks are long-running (e.g. long HTTP handlers, DB batches); forgetting that blocked Submit waits until a worker is free.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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