micro/go-micro · error
invalid connection from pool
Error message
invalid connection from pool
What it means
When the NATS broker is configured with a connection pool, Publish checks out a pooled connection and verifies its underlying *nats.Conn is non-nil. If the pool hands back an entry whose connection is nil (a stale or improperly released pooled entry), Publish returns this error instead of panicking on a nil dereference. It indicates pool corruption or a connection that was closed and zeroed out without being evicted.
Source
Thrown at broker/nats/nats.go:240
n.RLock()
defer n.RUnlock()
b, err := n.opts.Codec.Marshal(msg)
if err != nil {
return err
}
// Use connection pool if enabled
if n.pool != nil {
poolConn, err := n.pool.Get()
if err != nil {
return err
}
defer func() { _ = n.pool.Put(poolConn) }()
conn := poolConn.Conn()
if conn == nil {
return errors.New("invalid connection from pool")
}
return conn.Publish(topic, b)
}
// Use single connection (original behavior)
if n.conn == nil {
return errors.New("not connected")
}
return n.conn.Publish(topic, b)
}
func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) {
n.RLock()
hasConnection := n.conn != nil || n.pool != nil
n.RUnlock()
if !hasConnection {View on GitHub (pinned to 24529f1404)
Solutions
- Call broker.Connect() again to rebuild the pool with fresh live connections, then retry Publish.
- Enable retry: reconnect the NATS client (nats.RetryOnFailedConnect, MaxReconnects) so closed pooled connections are re-established.
- Check for concurrent broker.Disconnect()/Close() racing Publish; guard shutdown with proper synchronization.
- Upgrade/patch the pool implementation so closed connections are evicted rather than reused.
Example fix
// before
if err := broker.Publish(ctx, "events", msg); err != nil {
return err
}
// after
if err := broker.Publish(ctx, "events", msg); err != nil {
if strings.Contains(err.Error(), "invalid connection from pool") {
if cerr := broker.Connect(ctx); cerr != nil {
return cerr
}
return broker.Publish(ctx, "events", msg)
}
return err
} Defensive patterns
Strategy: retry
Validate before calling
// Before publishing, sanity-check NATS server reachability:
nc, err := nats.Connect(natsURL, nats.Timeout(2*time.Second))
if err != nil { return fmt.Errorf("nats unreachable: %w", err) }
if nc.Status() != nats.CONNECTED { return errors.New("nats not connected") }
nc.Close() Type guard
func isInvalidPoolConn(err error) bool {
return err != nil && strings.Contains(err.Error(), "invalid connection from pool")
} Try / catch
err := br.Publish(ctx, topic, msg)
if err != nil && strings.Contains(err.Error(), "invalid connection from pool") {
// rebuild pool / reconnect, then retry once
if cerr := br.Connect(ctx); cerr == nil {
err = br.Publish(ctx, topic, msg)
}
}
return err Prevention
- Configure the NATS client with MaxReconnects and RetryOnFailedConnect so pooled connections re-establish after server restarts.
- Avoid racing broker.Disconnect()/Close() against in-flight Publish calls; synchronize shutdown.
- Monitor NATS reconnect events and alert on pools serving closed connections.
- Keep the broker/pool dependency updated so stale pooled entries are evicted on close.
When it happens
Trigger: Publishing with pooled mode enabled (n.pool != nil) when a pooled entry's Conn() returns nil — e.g. a pooled connection was closed elsewhere (NATS server restart, explicit Close) but its wrapper stayed in the pool at broker/nats/nats.go:240.
Common situations: NATS server restart or network drop that closes pooled connections while the broker keeps serving them from the pool; concurrent Close/Publish races; misconfigured pool warm-up creating placeholder entries with nil connections.
Related errors
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/1d827d927b794d3d.
Report an issue: GitHub.