{"record":{"id":"402deb1f064b2f34","repo":"grpc/grpc-go","slug":"protocol-v-is-already-registered","errorCode":null,"errorMessage":"protocol %v is already registered","messagePattern":"protocol (.+?) is already registered","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"credentials/alts/internal/conn/record.go","lineNumber":108,"sourceCode":"\tpool, err := imem.NewDirtyBinaryTieredBufferPool(\n\t\t8,\n\t\t12, // Go page size, 4KB\n\t\t14, // 16KB (max HTTP/2 frame size used by gRPC)\n\t\t15, // 32KB (default buffer size for gRPC)\n\t\t16, // 64KB\n\t\t17, // 128KB\n\t\t19, // 512KB, max write buffer size\n\t)\n\tif err != nil {\n\t\tpanic(fmt.Sprintf(\"Failed to create write buffer pool: %v\", err))\n\t}\n\twriteBufPool = pool\n}\n\n// RegisterProtocol register a ALTS record encryption protocol.\nfunc RegisterProtocol(protocol string, f ALTSRecordFunc) error {\n\tif _, ok := protocols[protocol]; ok {\n\t\treturn fmt.Errorf(\"protocol %v is already registered\", protocol)\n\t}\n\tprotocols[protocol] = f\n\treturn nil\n}\n\n// conn represents a secured connection. It implements the net.Conn interface.\ntype conn struct {\n\tnet.Conn\n\treader readyreader.Reader\n\tcrypto ALTSRecordCrypto\n\t// buf holds data that has been read from the connection and decrypted,\n\t// but has not yet been returned by Read. It is a sub-slice of protected.\n\tbuf                []byte\n\tpayloadLengthLimit int\n\t// protectedHandle buffer holds data read from the network but have not yet\n\t// been decrypted. This data might not compose a complete frame.\n\t//\n\t// The buffer pointer to points to a buffer from the readBufPool. The handle","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/credentials/alts/internal/conn/record.go#L90-L126","documentation":"Returned by conn.RegisterProtocol when an ALTS record protocol name has already been registered in the package-level 'protocols' map. RegisterProtocol is idempotent-fail: the second registration of the same name is rejected. The init() in handshaker.go registers 'ALTSRP_GCM_AES128_REKEY' exactly once; a duplicate would come from user code or a double init.","triggerScenarios":"Calling conn.RegisterProtocol(\"ALTSRP_GCM_AES128_REKEY\", fn) from application/test code after handshaker.init() already registered it, or importing two packages that both register the same protocol name.","commonSituations":"Test code that registers a custom or mock ALTS record protocol with a name colliding with the built-in one; a fork or custom build that adds its own init() registering ALTSRP_GCM_AES128_REKEY; running tests that re-execute registration without resetting the map.","solutions":["Do not call conn.RegisterProtocol yourself unless you are introducing a genuinely new protocol — the built-in one is registered automatically.","Use a unique protocol name for custom/test ALTS record implementations.","In tests, avoid re-importing or re-initializing the handshaker package; if a global map reset is needed, guard registration with a sync.Once or check existence first."],"exampleFix":"// before\nconn.RegisterProtocol(\"ALTSRP_GCM_AES128_REKEY\", myFunc) // already registered -> error\n\n// after: use a unique name for custom protocols\nconn.RegisterProtocol(\"MY_CUSTOM_ALTSRP\", myFunc)","handlingStrategy":"validation","validationCode":"// If you must register a custom protocol, check first to avoid the duplicate error.\nfunc safeRegisterProtocol(name string, f conn.ALTSRecordFunc) error {\n    // conn.RegisterProtocol returns an error on duplicate; the public API already does this,\n    // so just handle the returned error instead of ignoring it.\n    if err := conn.RegisterProtocol(name, f); err != nil {\n        log.Printf(\"protocol registration skipped: %v\", err)\n        return nil // treat duplicate as non-fatal\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not call conn.RegisterProtocol for the built-in ALTSRP_GCM_AES128_REKEY — it is registered in init().","Use unique names for test/custom protocols.","Guard test-only registration with sync.Once or a build-tagged init."],"tags":["grpc","alts","registration","init","duplicate"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}