{"record":{"id":"1eaff3d26805e127","repo":"panjf2000/ants","slug":"too-many-goroutines-blocked-on-submit-or-nonblocki","errorCode":null,"errorMessage":"too many goroutines blocked on submit or Nonblocking is set","messagePattern":"too many goroutines blocked on submit or Nonblocking is set","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"ants.go","lineNumber":73,"sourceCode":"\t// OPENED represents that the pool is opened.\n\tOPENED = iota\n\n\t// CLOSED represents that the pool is closed.\n\tCLOSED\n)\n\nvar (\n\t// ErrLackPoolFunc will be returned when invokers don't provide function for pool.\n\tErrLackPoolFunc = errors.New(\"must provide function for pool\")\n\n\t// ErrInvalidPoolExpiry will be returned when setting a negative number as the periodic duration to purge goroutines.\n\tErrInvalidPoolExpiry = errors.New(\"invalid expiry for pool\")\n\n\t// ErrPoolClosed will be returned when submitting task to a closed pool.\n\tErrPoolClosed = errors.New(\"this pool has been closed\")\n\n\t// ErrPoolOverload will be returned when the pool is full and no workers available.\n\tErrPoolOverload = errors.New(\"too many goroutines blocked on submit or Nonblocking is set\")\n\n\t// ErrInvalidPreAllocSize will be returned when trying to set up a negative capacity under PreAlloc mode.\n\tErrInvalidPreAllocSize = errors.New(\"can not set up a negative capacity under PreAlloc mode\")\n\n\t// ErrTimeout will be returned after the operations timed out.\n\tErrTimeout = errors.New(\"operation timed out\")\n\n\t// ErrInvalidPoolIndex will be returned when trying to retrieve a pool with an invalid index.\n\tErrInvalidPoolIndex = errors.New(\"invalid pool index\")\n\n\t// ErrInvalidLoadBalancingStrategy will be returned when trying to create a MultiPool with an invalid load-balancing strategy.\n\tErrInvalidLoadBalancingStrategy = errors.New(\"invalid load-balancing strategy\")\n\n\t// ErrInvalidMultiPoolSize  will be returned when trying to create a MultiPool with an invalid size.\n\tErrInvalidMultiPoolSize = errors.New(\"invalid size for multiple pool\")\n\n\t// workerChanCap determines whether the channel of a worker should be a buffered channel\n\t// to get the best performance. Inspired by fasthttp at","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/panjf2000/ants/blob/107e37678122b00e1b365636ce4f80623ba41579/ants.go#L55-L91","documentation":"ErrPoolOverload is returned by retrieveWorker (ants.go:534) when a task cannot be enqueued because the pool is at capacity and the caller opted out of blocking: either Nonblocking is set, or MaxBlockingTasks is non-zero and the number of already-waiting submissions has reached that limit. It is a back-pressure signal, not a crash.","triggerScenarios":"pool.Submit on a full pool created with ants.WithNonblocking(true); or with WithMaxBlockingTasks(n) when p.Waiting() >= n and no worker is free.","commonSituations":"Producers outpacing workers during traffic spikes; misconfigured MaxBlockingTasks lower than burst concurrency; deliberately using nonblocking mode for load shedding.","solutions":["Handle the error at the call site: drop, defer, or requeue the task (this is the intended use in nonblocking mode).","Increase pool capacity (raise size in NewPool or adjust options) to match producer throughput.","Raise/remove MaxBlockingTasks to allow more submissions to queue, or remove WithNonblocking to let Submit block.","Add retry with backoff if tasks must not be lost."],"exampleFix":"// before\nif err := pool.Submit(task); err != nil {\n    panic(err)\n}\n// after\nif errors.Is(err, ants.ErrPoolOverload) {\n    metrics.Inc(\"pool_overload\")\n    go func() { _ = queue.PushBack(task) }() // shed/load-shape instead of panic\n}","handlingStrategy":"retry","validationCode":"if pool.Cap() > 0 && pool.Waiting() >= maxBlockingTasks && !blockingAllowed {\n    // shed or requeue before calling Submit\n}","typeGuard":null,"tryCatchPattern":"err := pool.Submit(task)\nif errors.Is(err, ants.ErrPoolOverload) {\n    metrics.Inc(\"pool_overload\")\n    time.AfterFunc(backoff, func() { _ = pool.Submit(task) })\n}","preventionTips":["Size the pool against peak producer throughput; monitor pool.Running() and pool.Waiting().","Only use WithNonblocking when dropping tasks is acceptable (load shedding).","Set MaxBlockingTasks generously enough for bursts, and queue tasks yourself with backpressure."],"tags":["go","backpressure","concurrency","capacity"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"107e37678122b00e1b365636ce4f80623ba41579","analyzedAt":"2026-09-06T13:28:28.492Z","contentChangedAt":"2026-09-06T13:28:28.492Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}