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
- 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).
- Ensure the xDS control plane is not sending incomplete or empty security policy updates that clear the HandshakeInfo.
- Verify the grpc-go client version is compatible with the xDS server version so security config fields are parsed correctly.
- 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
- Monitor xDS resource updates and alert on security policy removals.
- Keep grpc-go and xDS server versions aligned to avoid config field misinterpretation.
- Use stable xDS security configurations to avoid frequent HandshakeInfo replacement.
- Implement reconnection backoff so transient xDS races self-heal.
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
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- xds: CertificateProvider to fetch trusted roots is missing,
- xds: CertificateProvider to fetch identity certificate is mi
- overriding server name is not supported by xDS client TLS cr
- server handshake is not supported by xDS client TLS credenti
- failed to build credentials bundle from bootstrap for %q: %v
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/a43b310396e02c2d.
Report an issue: GitHub.