{"record":{"id":"f05fc391f255c33e","repo":"micro/go-micro","slug":"connection-pool-exhausted","errorCode":null,"errorMessage":"connection pool exhausted","messagePattern":"connection pool exhausted","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/nats/pool.go","lineNumber":13,"sourceCode":"package nats\n\nimport (\n\t\"errors\"\n\t\"sync\"\n\t\"time\"\n\n\tnatsp \"github.com/nats-io/nats.go\"\n)\n\nvar (\n\t// ErrPoolExhausted is returned when no connections are available in the pool\n\tErrPoolExhausted = errors.New(\"connection pool exhausted\")\n\t// ErrPoolClosed is returned when trying to use a closed pool\n\tErrPoolClosed = errors.New(\"connection pool is closed\")\n)\n\n// connectionPool manages a pool of NATS connections\ntype connectionPool struct {\n\tmu          sync.RWMutex\n\tconnections chan *pooledConnection\n\tfactory     func() (*natsp.Conn, error)\n\tsize        int\n\tidleTimeout time.Duration\n\tclosed      bool\n}\n\n// pooledConnection wraps a NATS connection with metadata\ntype pooledConnection struct {\n\tconn      *natsp.Conn\n\tcreatedAt time.Time","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/transport/nats/pool.go#L1-L31","documentation":"ErrPoolExhausted is the sentinel returned by the NATS connection pool when a caller requests a connection and all pooled connections are checked out (the internal connections channel is empty). Pool size is fixed at creation, so concurrency above that limit triggers this error.","triggerScenarios":"Calling pool.Get() (or Dial when pooling enabled) while every connection in the fixed-size pool is currently borrowed and not yet returned via Put.","commonSituations":"Burst of concurrent requests exceeding pool size; leaked connections from code paths that Get without Put (error paths, panics); pool sized too small for service concurrency; slow operations holding connections long.","solutions":["Increase the pool size at transport creation to cover peak concurrency","Ensure every Get has a matching Put, including on error paths (defer put)","Add retry/backoff around Get to ride out transient exhaustion","Check for stuck/leaked connections holding the pool indefinitely"],"exampleFix":"// before\nconn, _ := pool.Get(ctx) // fails under burst\n// after\nconn, err := pool.Get(ctx)\nif errors.Is(err, nats.ErrPoolExhausted) {\n\ttime.Sleep(50 * time.Millisecond)\n\tconn, err = pool.Get(ctx)\n}\ndefer pool.Put(conn)","handlingStrategy":"retry","validationCode":"// limit concurrency to pool size before calling Get\nsem := make(chan struct{}, poolSize)\nsem <- struct{}{}\ndefer func() { <-sem }()","typeGuard":null,"tryCatchPattern":"conn, err := pool.Get(ctx)\nif errors.Is(err, nats.ErrPoolExhausted) {\n\tselect {\n\tcase <-time.After(100 * time.Millisecond):\n\t\tconn, err = pool.Get(ctx)\n\tcase <-ctx.Done():\n\t\treturn ctx.Err()\n\t}\n}","preventionTips":["Always defer pool.Put(conn) immediately after a successful Get","Size the pool for peak concurrent requests plus headroom","Add metrics/alerts on pool in-use count","Use bounded concurrency (semaphores) around pooled calls"],"tags":["nats","connection-pool","exhaustion","concurrency"],"backgroundTag":"connection-pool-exhausted","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}