grpc/grpc-go · error
failed to receive ALTS handshaker response
Error message
failed to receive ALTS handshaker response: %w
What it means
Returned by accessHandshakerService when receiving a HandshakerResp on the open DoHandshake stream fails (h.stream.Recv returns an error). The underlying error is wrapped with %w. This indicates the control stream to the GCP handshaker service broke after a request was sent.
Solutions
- Retry the ALTS handshake/connection — transient.
- Inspect the wrapped error: io.EOF often means the handshaker service closed the stream; context.Canceled/DeadlineExceeded means the caller's deadline was too short.
- Verify metadata-server reachability and health; check GCP status.
- Increase handshake deadlines if large handshakes are timing out.
Defensive patterns
Strategy: retry
Try / catch
// Stream Recv failures during handshake are typically transient; retry.
if err != nil {
if errors.Is(err, io.EOF) {
// handshaker service closed the stream; retry the handshake
}
if errors.Is(err, context.DeadlineExceeded) {
// increase handshake deadline
}
} Prevention
- Provide an adequately long context deadline for ALTS handshakes.
- Distinguish io.EOF (service closed) from context cancellation when triaging.
- Alert on sustained Recv failures against the metadata server.
When it happens
Trigger: After successfully Sending a HandshakerReq, Recv() on the same stream returns an error (EOF, transport error, RST_STREAM). Reached during every doHandshake iteration and the processUntilDone loop.
Common situations: Handshaker service crashed/restarted mid-handshake; network drop to the metadata server; the stream was cancelled by context timeout; the peer sent no more frames causing processUntilDone to loop and eventually fail Recv; RPC-level error from the handshaker service causing the stream to terminate.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to send ALTS handshaker request
- failed to establish stream to ALTS handshaker service
- %v
- client-side RPC versions is not compatible with this…
- failed to create a stream to external processor
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/e05e48a7ef5d4fee.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/alts/internal/handshaker/handshaker.go:309
}
maxFrameSize := int(envconfig.ALTSMaxFrameSize)
if peerMax := int(result.GetMaxFrameSize()); peerMax > 0 {
maxFrameSize = min(peerMax, maxFrameSize)
}
sc, err := conn.NewConnWithMaxFrameSize(h.conn, h.side, result.GetRecordProtocol(), result.KeyData[:keyLen], extra, maxFrameSize)
if err != nil {
return nil, nil, err
}
return sc, result, nil
}
func (h *altsHandshaker) accessHandshakerService(req *altspb.HandshakerReq) (*altspb.HandshakerResp, error) {
if err := h.stream.Send(req); err != nil {
return nil, fmt.Errorf("failed to send ALTS handshaker request: %w", err)
}
resp, err := h.stream.Recv()
if err != nil {
return nil, fmt.Errorf("failed to receive ALTS handshaker response: %w", err)
}
return resp, nil
}
// processUntilDone processes the handshake until the handshaker service returns
// the results. Handshaker service takes care of frame parsing, so we read
// whatever received from the network and send it to the handshaker service.
func (h *altsHandshaker) processUntilDone(resp *altspb.HandshakerResp, extra []byte) (*altspb.HandshakerResult, []byte, error) {
var lastWriteTime time.Time
buf := make([]byte, frameLimit)
for {
if len(resp.OutFrames) > 0 {
lastWriteTime = time.Now()
if _, err := h.conn.Write(resp.OutFrames); err != nil {
return nil, nil, err
}
}
if resp.Result != nil {View on GitHub (pinned to 0c51461d27)