grpc/grpc-go · warning
grpc: the connection is closing due to channel idleness
Error message
grpc: the connection is closing due to channel idleness
What it means
Internal sentinel errConnIdling (clientconn.go:75-77) passed to tearDown when the channel moves into IDLE after the idle timeout. In enterIdleMode (clientconn.go:463-466) every addrConn is torn down with errConnIdling, closing the transport without failing already-started RPCs. New RPCs or an explicit Connect() exit idle.
Source
Thrown at clientconn.go:77
const (
// minimum time to give a connection to complete
minConnectTimeout = 20 * time.Second
)
var (
// ErrClientConnClosing indicates that the operation is illegal because
// the ClientConn is closing.
//
// Deprecated: this error should not be relied upon by users; use the status
// code of Canceled instead.
ErrClientConnClosing = status.Error(codes.Canceled, "grpc: the client connection is closing")
// errConnDrain indicates that the connection starts to be drained and does not accept any new RPCs.
errConnDrain = errors.New("grpc: the connection is drained")
// errConnClosing indicates that the connection is closing.
errConnClosing = errors.New("grpc: the connection is closing")
// errConnIdling indicates the connection is being closed as the channel
// is moving to an idle mode due to inactivity.
errConnIdling = errors.New("grpc: the connection is closing due to channel idleness")
// invalidDefaultServiceConfigErrPrefix is used to prefix the json parsing error for the default
// service config.
invalidDefaultServiceConfigErrPrefix = "grpc: the provided default service config is invalid"
// PickFirstBalancerName is the name of the pick_first balancer.
PickFirstBalancerName = pickfirst.Name
)
// The following errors are returned from Dial and DialContext
var (
// errNoTransportSecurity indicates that there is no transport security
// being set for ClientConn. Users should either set one or explicitly
// call WithInsecure DialOption to disable security.
errNoTransportSecurity = errors.New("grpc: no transport security set (use grpc.WithTransportCredentials(insecure.NewCredentials()) explicitly or set credentials)")
// errTransportCredsAndBundle indicates that creds bundle is used together
// with other individual Transport Credentials.
errTransportCredsAndBundle = errors.New("grpc: credentials.Bundle may not be used with individual TransportCredentials")
// errNoTransportCredsInBundle indicated that the configured creds bundle
// returned a transport credentials which was nil.View on GitHub (pinned to 03255a9237)
Solutions
- Call cc.Connect() to force the channel out of IDLE before issuing RPCs, or issue RPCs with grpc.WaitForReady(true) so they block through reconnection.
- Tune the idle timeout via grpc.WithIdleTimeout(d) — set it longer or to 0 to disable idling entirely if the reconnection cost is unacceptable.
- Keep the channel warm with a lightweight health-check RPC if you must avoid idle transitions.
- Distinguish errConnIdling from a real failure: it is expected behavior, not a backend problem.
Example fix
// before — default idle timeout fires, first RPC after quiet period stalls/fails cc, _ := grpc.NewClient(target) // ... 35 minutes pass ... client.SayHello(ctx, req) // channel was idling // after — disable idle, or explicitly reconnect cc, _ := grpc.NewClient(target, grpc.WithIdleTimeout(0)) // never idle // or cc.Connect() client.SayHello(ctx, req, grpc.WaitForReady(true))
Defensive patterns
Strategy: retry
Validate before calling
// Force the channel out of idle before issuing RPCs cc.Connect() // exits IDLE if necessary client.SayHello(ctx, req, grpc.WaitForReady(true))
Try / catch
if status.Code(err) == codes.Unavailable && /* idling */ cc.GetState() == connectivity.Idle {
cc.Connect(); /* retry */
} Prevention
- Tune grpc.WithIdleTimeout for your traffic pattern (0 disables).
- Call cc.Connect() proactively on quiet channels.
- Use WaitForReady(true) after quiet periods.
When it happens
Trigger: The channel's idle timer fires (default WithIdleTimeout — 30m in recent versions, 0 disables) because no RPCs were issued for the period; the idleness manager calls enterIdleMode which tears subchannels down with errConnIdling. A subsequent pick against a stale SubConn surfaces it.
Common situations: Low-traffic services that go quiet long enough to hit the idle timeout; default idle timeout enabled unexpectedly after a grpc-go upgrade; observability picking up the teardown as an error; bursts after quiet periods.
Related errors
- grpc: the connection is closing
- no SubConn is available
- grpc: the connection is drained
- all SubConns are in TransientFailure
- bad resolver state
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/d5760150a7962906.
Report an issue: GitHub.