grpc/grpc-go · error

xds: connection closed or HandshakeInfo dead

Error message

xds: connection closed or HandshakeInfo dead

What it means

Returned by ClientSideTLSConfig when the atomic pointer holding the reference-counted HandshakeInfo loads as nil. This means the xDS security configuration for the cluster was torn down or replaced before the TLS handshake could read it, so there is no live security config to use. The client cannot build a tls.Config and the handshake aborts. It is an internal xDS-credentials error surfaced during connection setup or reconfiguration.

Source

Thrown at internal/credentials/xds/handshake_info.go:136

		hi.rootProvider.Close()
	}
	if hi.identityProvider != nil {
		hi.identityProvider.Close()
	}
}

// ClientSideTLSConfig loads the HandshakeInfo from hiPtr, marks it as in-use,
// and returns the tls.Config along with a done callback that MUST be invoked
// when the handshake completes. If no HandshakeInfo is stored in hiPtr or if
// fallback credentials should be used, useFallback returns true.
func ClientSideTLSConfig(ctx context.Context, hiPtr *atomic.Pointer[grpcsync.RefCounted[HandshakeInfo]], hostname string) (cfg *tls.Config, useFallback bool, done func(), err error) {
	if hiPtr == nil {
		return nil, true, func() {}, nil
	}
	for {
		hiRC := hiPtr.Load()
		if hiRC == nil {
			return nil, false, func() {}, errors.New("xds: connection closed or HandshakeInfo dead")
		}
		if !hiRC.TryIncrement() {
			if hiPtr.Load() != hiRC {
				continue
			}
			return nil, false, func() {}, errors.New("xds: connection closed or HandshakeInfo dead")
		}

		hi := hiRC.Value()
		if hi == nil || hi.UseFallbackCreds() {
			hiRC.Decrement()
			return nil, true, func() {}, nil
		}
		cfg, err := hi.clientSideTLSConfigInternal(ctx, hostname)
		if err != nil {
			hiRC.Decrement()
			return nil, false, func() {}, err
		}

View on GitHub (pinned to 0c51461d27)

Solutions

  1. Check the xDS management server logs and LDS/CDS resources to confirm the cluster still has a valid security configuration (DownstreamTLSContext with certificate validation context).
  2. Ensure the xDS control plane is not sending incomplete or empty security policy updates that clear the HandshakeInfo.
  3. Verify the grpc-go client version is compatible with the xDS server version so security config fields are parsed correctly.
  4. Use fallback credentials (the function returns useFallback=true when HandshakeInfo is genuinely absent) so non-xDS TLS paths work while xDS converges.

Example fix

// The error is internal; ensure xDS config has valid security policy.
// In your xDS management server, provide a DownstreamTLSContext:
// before (misconfigured): no security policy on cluster
// after:
{
  "validation_context": {
    "trusted_ca": { "filename": "/etc/ssl/certs/ca-cert.pem" }
  }
}
Defensive patterns

Strategy: retry

Validate before calling

// Before relying on xDS TLS, verify the channel is READY and xDS has converged.
// There is no pre-call validation for internal HandshakeInfo state; use connection state.
conn, err := grpc.DialContext(ctx, target,
    grpc.WithBlock(),
    grpc.WithReturnConnectionError(),
)
if err != nil { log.Fatal(err) }

Try / catch

// In Go, check the error from RPC calls; gRPC will fail RPCs when xDS security config is missing.
err := client.Call(ctx, req)
if err != nil {
    if strings.Contains(err.Error(), "connection closed or HandshakeInfo dead") {
        // xDS reconfiguration race; reconnect or back off and retry
        backoff.Retry(ctx, retryCall)
    }
}

Prevention

When it happens

Trigger: Calling ClientSideTLSConfig (via grpc.Dial with xds credentials) when the HandshakeInfo atomic pointer has been cleared—i.e., during xDS cluster/security-config removal, connection close, or a config update that swaps the pointer to nil. Occurs in the for-loop at handshake_info.go:134-136 when hiPtr.Load() returns nil on the first iteration.

Common situations: xDS management server pushes a security policy removal while RPCs are in-flight; cluster teardown during graceful shutdown; control plane (Istio/Envoy/xDS server) misconfiguration that drops the CertificateValidation/DownstreamTLSContext mid-session; version mismatch between grpc-go and the xDS server where security config fields are unrecognized and silently dropped.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/a43b310396e02c2d. Report an issue: GitHub.