grpc/grpc-go · error
received frame with incorrect message type
Error message
received frame with incorrect message type %v, expected lower byte %v
What it means
Returned during ALTS record reading when the 4-byte little-endian message type field's lowest byte does not equal altsRecordMsgType (0x06). The ALTS record format mandates a message type whose low byte is 0x06; a mismatch means the data on the wire is not a valid ALTS record.
Solutions
- Confirm both endpoints are using ALTS transport credentials (not mixing ALTS with TLS or insecure).
- Check for a proxy, sidecar, or load balancer that may be speaking a different protocol on the wire.
- Capture a packet trace to confirm whether the bytes are valid ALTS records.
- Close the connection; it cannot recover once framing is desynchronized.
Defensive patterns
Strategy: try-catch
Try / catch
// Wrong message type => not ALTS data on this connection; treat as fatal.
if err != nil && strings.Contains(err.Error(), "incorrect message type") {
log.Printf("non-ALTS data on ALTS connection: %v", err)
return err // let gRPC reconnect or fail the RPC
} Prevention
- Ensure both endpoints use alts.NewClientCreds/NewServerCreds — do not mix with TLS or insecure.
- Check for proxies/sidecars that might inject non-ALTS bytes.
- Monitor for this error as a sign of misconfigured or hostile traffic.
When it happens
Trigger: A frame passes the length checks but its message-type byte differs from 0x06. Reached on every read of an ALTS connection after a complete frame is assembled.
Common situations: Non-ALTS data arriving on a connection that was supposed to be ALTS-secured (e.g. plaintext HTTP/2 or a different protocol); corruption of the message-type bytes; an interoperability mismatch with a peer using a different ALTS record format version.
Related errors
- received frame with size
- received the frame length
- client-side RPC versions is not compatible with this…
- failed to establish stream to ALTS handshaker service
- failed to receive ALTS handshaker response
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/0b2281f442437741.
Report an issue: GitHub.
Appendix: source
Thrown at credentials/alts/internal/conn/record.go:273
nRead, err := p.Conn.Read(protected[len(protected):cap(protected)])
if err != nil {
return nil, 0, err
}
protected = protected[:len(protected)+nRead]
}
framedMsg, p.nextFrame, err = ParseFramedMsg(protected, altsRecordLengthLimit)
if err != nil {
return nil, 0, err
}
}
// Now we have a complete frame, decrypted it.
msg := framedMsg[MsgLenFieldSize:]
if len(msg) < msgTypeFieldSize {
return nil, 0, fmt.Errorf("received frame with size %v which is shorter than message type field size %v", len(msg), msgTypeFieldSize)
}
msgType := binary.LittleEndian.Uint32(msg[:msgTypeFieldSize])
if msgType&0xff != altsRecordMsgType {
return nil, 0, fmt.Errorf("received frame with incorrect message type %v, expected lower byte %v",
msgType, altsRecordMsgType)
}
ciphertext := msg[msgTypeFieldSize:]
// Decrypt directly into the buffer, avoiding a copy from p.buf if
// possible.
if bufSize >= len(ciphertext) {
allocatedBuf := pool.Get(bufSize)
dec, err := p.crypto.Decrypt((*allocatedBuf)[:0], ciphertext)
if err != nil {
pool.Put(allocatedBuf)
return nil, 0, err
}
p.dropProtectedIfEmtpy()
return allocatedBuf, len(dec), nil
}
// Decrypt requires that if the dst and ciphertext alias, they
// must alias exactly. Code here used to use msg[:0], but msgView on GitHub (pinned to 0c51461d27)