micro/go-micro · error
invalid connection from pool
Error message
invalid connection from pool
What it means
Dial consults the connection pool when pooling is enabled. If a pooled *pooledConnection's underlying nats.Conn is nil (e.g. the connection was closed or failed after being returned to the pool), Dial puts it back and returns this error. It signals a corrupted/invalid pooled connection rather than a dial failure.
Source
Thrown at transport/nats/nats.go:414
var c *nats.Conn
var pooledConn *pooledConnection
var err error
// Use connection pool if available
n.mu.RLock()
hasPool := n.pool != nil
n.mu.RUnlock()
if hasPool {
pooledConn, err = n.pool.Get()
if err != nil {
return nil, err
}
c = pooledConn.Conn()
if c == nil {
_ = n.pool.Put(pooledConn)
return nil, errors.New("invalid connection from pool")
}
} else {
// Create a new connection (original behavior)
opts := n.nopts
opts.Servers = n.addrs
opts.Secure = n.opts.Secure
opts.TLSConfig = n.opts.TLSConfig
opts.Timeout = dopts.Timeout
// secure might not be set
if n.opts.TLSConfig != nil {
opts.Secure = true
}
c, err = opts.Connect()
if err != nil {
return nil, err
}View on GitHub (pinned to 24529f1404)
Solutions
- Enable/verify pool health pruning so closed conns are evicted instead of handed out
- Reduce pool max-idle/keepalive so stale connections expire before reuse
- Retry the Dial once — subsequent pool gets may return a valid connection
- Upgrade/patch pool.Get to validate Conn() before returning, re-putting dead entries
Example fix
// caller-side before
conn, err := t.Dial("nats", dialOpts)
if err != nil { return err }
// after
var conn transport.Client
for i := 0; i < 2; i++ {
conn, err = t.Dial("nats", dialOpts)
if err == nil { break }
} Defensive patterns
Strategy: retry
Validate before calling
conn, err := t.Dial("nats", opts...)
if err != nil {
if strings.Contains(err.Error(), "invalid connection from pool") {
conn, err = t.Dial("nats", opts...) // fresh attempt
}
} Try / catch
if err != nil && strings.Contains(err.Error(), "invalid connection from pool") {
// retry dial; if persistent, recreate the transport
return t.Dial("nats", opts...)
} Prevention
- Keep pool idle/keepalive settings below NATS server eviction limits
- Validate/reap dead connections in the pool before reuse
- Retry Dial on this specific error once before surfacing it
- Watch NATS server logs for dropped idle connections
When it happens
Trigger: Calling transport.Dial on a NATS transport with connection pooling enabled (pool created via NewTransport pool options) when the pool hands back an entry whose Conn() is nil — typically after the server dropped the connection.
Common situations: Idle connections reaped by NATS server max-age/limits; pool not pruning closed connections; server restart leaving stale entries in the pool; long-running services where pooled conns expire.
Related errors
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/b4cd632ed0470872.
Report an issue: GitHub.