grpc/grpc-go · error
failed to establish stream to ALTS handshaker service: %v
Error message
failed to establish stream to ALTS handshaker service: %v
What it means
In altsHandshaker.ClientHandshake (handshaker.go:170-174), the client opens a bidirectional streaming RPC (DoHandshake) to the ALTS handshaker service running on GCP via h.clientConn. If that gRPC stream cannot be established, the error is wrapped as "failed to establish stream to ALTS handshaker service". The clientConn is the one returned by service.Dial(hsAddress).
Source
Thrown at credentials/alts/internal/handshaker/handshaker.go:173
// ClientHandshake starts and completes a client ALTS handshake for GCP. Once
// done, ClientHandshake returns a secure connection.
func (h *altsHandshaker) ClientHandshake(ctx context.Context) (net.Conn, credentials.AuthInfo, error) {
if err := clientHandshakes.Acquire(ctx, 1); err != nil {
return nil, nil, err
}
defer clientHandshakes.Release(1)
if h.side != core.ClientSide {
return nil, nil, errors.New("only handshakers created using NewClientHandshaker can perform a client handshaker")
}
// TODO(matthewstevenson88): Change unit tests to use public APIs so
// that h.stream can unconditionally be set based on h.clientConn.
if h.stream == nil {
stream, err := altsgrpc.NewHandshakerServiceClient(h.clientConn).DoHandshake(ctx)
if err != nil {
return nil, nil, fmt.Errorf("failed to establish stream to ALTS handshaker service: %v", err)
}
h.stream = stream
}
// Create target identities from service account list.
targetIdentities := make([]*altspb.Identity, 0, len(h.clientOpts.TargetServiceAccounts))
for _, account := range h.clientOpts.TargetServiceAccounts {
targetIdentities = append(targetIdentities, &altspb.Identity{
IdentityOneof: &altspb.Identity_ServiceAccount{
ServiceAccount: account,
},
})
}
req := &altspb.HandshakerReq{
ReqOneof: &altspb.HandshakerReq_ClientStart{
ClientStart: &altspb.StartClientHandshakeReq{
HandshakeSecurityProtocol: hsProtocol,
ApplicationProtocols: appProtocols,View on GitHub (pinned to 03255a9237)
Solutions
- Confirm the workload is actually on GCP and the ALTS handshaker service is reachable (ErrUntrustedPlatform is a related earlier guard).
- Check the inner %v for the stream RPC error (UNAVAILABLE, DEADLINE_EXCEEDED, PERMISSION_DENIED) and address it.
- If not on GCP, switch to TLS credentials instead of ALTS.
Example fix
// before
creds, _ := alts.NewClientCreds(...)
conn, _ := grpc.NewClient(target, grpc.WithTransportCredentials(creds)) // off GCP
// after (off GCP)
creds := credentials.NewTLS(&tls.Config{ServerName: target})
conn, _ := grpc.NewClient(target, grpc.WithTransportCredentials(creds)) Defensive patterns
Strategy: try-catch
Validate before calling
// Confirm you are on GCP before attempting ALTS; otherwise use TLS.
func onGCP() bool { _, err := metadata.Get("instance/zone"); return err == nil } Try / catch
secConn, authInfo, err := chs.ClientHandshake(ctx)
if err != nil {
if strings.Contains(err.Error(), "failed to establish stream to ALTS handshaker service") {
log.Printf("ALTS handshaker service unreachable: %v; falling back to TLS", err)
// fall back to a TLS credentials handshake instead
}
return nil, nil, err
} Prevention
- Gate ALTS usage behind a GCP-platform check; use TLS elsewhere.
- Ensure the ALTS handshaker service address/port is reachable (firewall, metadata).
- Retry with backoff on transient UNAVAILABLE from the handshaker service.
When it happens
Trigger: Performing an ALTS client handshake when the connection to the local ALTS handshaker service (the GCP ALTS-MDB endpoint) cannot be opened — network error, service unavailable, deadline, or auth failure talking to the handshaker service.
Common situations: Running ALTS outside GCP (where the handshaker service is absent); GCP metadata server / ALTS daemon not reachable; firewall blocking the handshaker service port; transient GCP control-plane issue; the hsAddress is misconfigured.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- server-side RPC versions are not compatible with this client
- client-side RPC versions is not compatible with this server,
- received the frame length %d larger than the limit %d
- negotiated unknown next_protocol %q
- protocol %q: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/1a072e1cf4ad75c5.
Report an issue: GitHub.