{"record":{"id":"e8cbb2e9661c7ec4","repo":"grpc/grpc-go","slug":"negotiated-unknown-next-protocol-q","errorCode":null,"errorMessage":"negotiated unknown next_protocol %q","messagePattern":"negotiated unknown next_protocol %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/alts/internal/conn/record.go","lineNumber":147,"sourceCode":"\t// nextFrame stores the next frame (in protected buffer) info.\n\tnextFrame []byte\n\t// overhead is the calculated overhead of each frame.\n\toverhead  int\n\tconstPool constBufferPool // stored as a field to avoid heap allocations.\n}\n\n// NewConn creates a new secure channel instance given the other party role and\n// handshaking result.\nfunc NewConn(c net.Conn, side core.Side, recordProtocol string, key []byte, protected []byte) (net.Conn, error) {\n\treturn NewConnWithMaxFrameSize(c, side, recordProtocol, key, protected, 0)\n}\n\n// NewConnWithMaxFrameSize creates a new secure channel instance given the\n// other party role, handshaking result, and negotiated maximum frame size.\nfunc NewConnWithMaxFrameSize(c net.Conn, side core.Side, recordProtocol string, key []byte, protected []byte, negotiatedMaxFrameSize int) (net.Conn, error) {\n\tnewCrypto := protocols[recordProtocol]\n\tif newCrypto == nil {\n\t\treturn nil, fmt.Errorf(\"negotiated unknown next_protocol %q\", recordProtocol)\n\t}\n\tcrypto, err := newCrypto(side, key)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"protocol %q: %v\", recordProtocol, err)\n\t}\n\toverhead := MsgLenFieldSize + msgTypeFieldSize + crypto.EncryptionOverhead()\n\n\t// Clamp maxRecordLen to be at least altsRecordDefaultLength.\n\tmaxRecordLen := max(altsRecordDefaultLength, negotiatedMaxFrameSize)\n\tpayloadLengthLimit := maxRecordLen - overhead\n\t// We pre-allocate protected to be of size 32KB during initialization.\n\t// We increase the size of the buffer by the required amount if it can't\n\t// hold a complete encrypted record.\n\tprotectedHandle := readBufPool.Get(max(altsReadBufferInitialSize, len(protected)))\n\tprotectedBuf := *protectedHandle\n\t// Copy additional data from hanshaker service.\n\tcopy(protectedBuf, protected)\n\tprotectedBuf = protectedBuf[:len(protected)]","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/credentials/alts/internal/conn/record.go#L129-L165","documentation":"NewConnWithMaxFrameSize (record.go:144-148) looks up the negotiated record protocol name in the protocols map to obtain its crypto factory. If the handshake selected a next_protocol that has no registered factory, the secure connection cannot be created. The %q is the unknown protocol name returned by the ALTS handshaker.","triggerScenarios":"The ALTS handshake negotiates a record protocol (e.g. a newer ALTSRP_*) that this build of the conn package didn't register. Arises from version skew between the handshaker service result and the compiled-in crypto protocols.","commonSituations":"A newer handshaker service advertises a protocol the older client lib doesn't know; a custom/forked build missing an init() registration; mismatched gRPC versions across client and GCP handshaker.","solutions":["Update the gRPC/ALTS build so the negotiated protocol's factory is registered.","If custom, register your record protocol via conn.RegisterProtocol before handshaking.","Align client and handshaker-service versions so they negotiate a mutually known protocol."],"exampleFix":"// before: build missing ALTSRP_GCM registration\n// after\nimport _ \"google.golang.org/grpc/credentials/alts/internal/conn\"  // ensures init() registers protocols\n// or upgrade the gRPC module to a version that knows the negotiated protocol","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"c, err := conn.NewConnWithMaxFrameSize(raw, core.ClientSide, rp, key, protected, 0)\nif err != nil {\n    if strings.Contains(err.Error(), \"negotiated unknown next_protocol\") {\n        log.Printf(\"ALTS negotiated an unsupported protocol %q; upgrade gRPC\", rp)\n    }\n    return nil, err\n}","preventionTips":["Keep client and GCP handshaker service on compatible gRPC versions.","Register any custom record protocol before handshaking.","Log the negotiated protocol name for fast diagnosis."],"tags":["go","grpc","alts","security","versioning"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}