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

  1. 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.
  2. Tune the idle timeout via grpc.WithIdleTimeout(d) — set it longer or to 0 to disable idling entirely if the reconnection cost is unacceptable.
  3. Keep the channel warm with a lightweight health-check RPC if you must avoid idle transitions.
  4. 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

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


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/d5760150a7962906. Report an issue: GitHub.