grpc/grpc-go · error
unknown resulted record protocol
Error message
unknown resulted record protocol %v
What it means
Returned inside doHandshake when the completed HandshakerResult.RecordProtocol is not present in the local keyLength map (which only contains 'ALTSRP_GCM_AES128_REKEY' -> 44 bytes). Without a known key length, the handshake key cannot be truncated correctly, so the secure connection cannot be finalized.
Solutions
- Upgrade grpc-go to a version whose keyLength map includes the negotiated protocol.
- If using a custom handshaker service, have it negotiate 'ALTSRP_GCM_AES128_REKEY' for clients/servers built on this grpc-go version.
- Inspect HandshakerResult.RecordProtocol in logs to identify the unexpected protocol and file a grpc-go issue if against the standard GCP service.
Defensive patterns
Strategy: try-catch
Try / catch
// Unknown record protocol from handshaker => version skew; fail and upgrade.
if err != nil && strings.Contains(err.Error(), "unknown resulted record protocol") {
log.Printf("ALTS handshaker returned unsupported record protocol %v; upgrade grpc-go", err)
return err
} Prevention
- Pin grpc-go to a version that supports the record protocol your handshaker negotiates.
- If developing a new ALTS record protocol, add it to the keyLength map and RegisterProtocol before deploying.
- Ensure custom/mock handshakers return only registered protocols.
When it happens
Trigger: The GCP handshaker service completes a handshake and returns a result whose RecordProtocol is something other than ALTSRP_GCM_AES128_REKEY. doHandshake looks up keyLength[result.RecordProtocol], fails, and returns this error.
Common situations: Version skew: the GCP handshaker service (or a custom one) negotiated a newer/different record protocol than this grpc-go build understands; a custom handshaker returning a protocol name that isn't registered in the keyLength map; a test mock returning an arbitrary protocol string.
Related errors
- negotiated unknown next_protocol
- client-side RPC versions is not compatible with this…
- server-side RPC versions are not compatible with this…
- protocol
- failed to establish stream to ALTS handshaker service
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/378123f67a3c293d.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/alts/internal/handshaker/handshaker.go:290
}
}
var extra []byte
if req.GetServerStart() != nil {
if resp.GetBytesConsumed() > uint32(len(req.GetServerStart().GetInBytes())) {
return nil, nil, errOutOfBound
}
extra = req.GetServerStart().GetInBytes()[resp.GetBytesConsumed():]
}
result, extra, err := h.processUntilDone(resp, extra)
if err != nil {
return nil, nil, err
}
// The handshaker returns a 128 bytes key. It should be truncated based
// on the returned record protocol.
keyLen, ok := keyLength[result.RecordProtocol]
if !ok {
return nil, nil, fmt.Errorf("unknown resulted record protocol %v", result.RecordProtocol)
}
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 {View on GitHub (pinned to 0c51461d27)