grpc/grpc-go · error
protocol %v is already registered
Error message
protocol %v is already registered
What it means
RegisterProtocol (record.go:106-109) is the registry for ALTS record encryption protocols (e.g. ALTSRP_GCM). Registering a name that already exists in the protocols map returns this error to prevent silently shadowing a crypto implementation. This is normally called from package init().
Source
Thrown at credentials/alts/internal/conn/record.go:108
pool, err := imem.NewDirtyBinaryTieredBufferPool(
8,
12, // Go page size, 4KB
14, // 16KB (max HTTP/2 frame size used by gRPC)
15, // 32KB (default buffer size for gRPC)
16, // 64KB
17, // 128KB
19, // 512KB, max write buffer size
)
if err != nil {
panic(fmt.Sprintf("Failed to create write buffer pool: %v", err))
}
writeBufPool = pool
}
// RegisterProtocol register a ALTS record encryption protocol.
func RegisterProtocol(protocol string, f ALTSRecordFunc) error {
if _, ok := protocols[protocol]; ok {
return fmt.Errorf("protocol %v is already registered", protocol)
}
protocols[protocol] = f
return nil
}
// conn represents a secured connection. It implements the net.Conn interface.
type conn struct {
net.Conn
reader readyreader.Reader
crypto ALTSRecordCrypto
// buf holds data that has been read from the connection and decrypted,
// but has not yet been returned by Read. It is a sub-slice of protected.
buf []byte
payloadLengthLimit int
// protectedHandle buffer holds data read from the network but have not yet
// been decrypted. This data might not compose a complete frame.
//
// The buffer pointer to points to a buffer from the readBufPool. The handleView on GitHub (pinned to 03255a9237)
Solutions
- Avoid registering a protocol name more than once; rely on the package's own init() registration.
- If you have a vendored duplicate, deduplicate the dependency (go mod tidy / replace) so init() runs once.
- In tests, check protocols map membership before registering, or reset the registry in TestMain.
Example fix
// before
conn.RegisterProtocol("ALTSRP_GCM", newGCM)
// ... later in another init()
conn.RegisterProtocol("ALTSRP_GCM", newGCM) // error
// after
// remove the duplicate registration; rely on the canonical init() Defensive patterns
Strategy: validation
Validate before calling
// Guard against duplicate registration in tests or libraries.
func safeRegisterProtocol(name string, f conn.ALTSRecordFunc) error {
// no public getter; in tests, reset the map in TestMain or track names yourself
return conn.RegisterProtocol(name, f)
} Prevention
- Register protocols only via package init(); don't re-register manually.
- Deduplicate vendored copies of the alts/conn package.
- In tests, isolate the registry to avoid cross-test double registration.
When it happens
Trigger: Calling conn.RegisterProtocol twice with the same name — typically because two init() paths both register the same protocol, or a library is imported twice / vendored in two copies.
Common situations: Double-vendoring of the ALTS conn package; a test binary that registers a protocol already registered by the production init(); a fork that re-registers on top of the upstream registration.
Related errors
- server-side RPC versions are not compatible with this client
- client-side RPC versions is not compatible with this server,
- received the frame length %d larger than the limit %d
- negotiated unknown next_protocol %q
- protocol %q: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/402deb1f064b2f34.
Report an issue: GitHub.