{"record":{"id":"ba147ffa7cc70a1d","repo":"grpc/grpc-go","slug":"cannot-register-a-nil-codecv2","errorCode":null,"errorMessage":"cannot register a nil CodecV2","messagePattern":"cannot register a nil CodecV2","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"encoding/encoding_v2.go","lineNumber":65,"sourceCode":"// servers.\n//\n// The CodecV2 will be stored and looked up by result of its Name() method, which\n// should match the content-subtype of the encoding handled by the CodecV2.  This\n// is case-insensitive, and is stored and looked up as lowercase.  If the\n// result of calling Name() is an empty string, RegisterCodecV2 will panic. See\n// Content-Type on\n// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for\n// more details.\n//\n// If both a Codec and CodecV2 are registered with the same name, the CodecV2\n// will be used.\n//\n// NOTE: this function must only be called during initialization time (i.e. in\n// an init() function), and is not thread-safe.  If multiple Codecs are\n// registered with the same name, the one registered last will take effect.\nfunc RegisterCodecV2(codec CodecV2) {\n\tif codec == nil {\n\t\tpanic(\"cannot register a nil CodecV2\")\n\t}\n\tif codec.Name() == \"\" {\n\t\tpanic(\"cannot register CodecV2 with empty string result for Name()\")\n\t}\n\tcontentSubtype := strings.ToLower(codec.Name())\n\tregisteredCodecs[contentSubtype] = codec\n}\n\n// GetCodecV2 gets a registered CodecV2 by content-subtype, or nil if no CodecV2 is\n// registered for the content-subtype.\n//\n// The content-subtype is expected to be lowercase.\nfunc GetCodecV2(contentSubtype string) CodecV2 {\n\tc, _ := registeredCodecs[contentSubtype].(CodecV2)\n\treturn c\n}\n","sourceCodeStart":47,"sourceCodeEnd":82,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/encoding/encoding_v2.go#L47-L82","documentation":"CodecV2 (encoding/encoding_v2.go:30) is the newer, memory-pool-aware codec interface whose Marshal returns and Unmarshal accepts a mem.BufferSlice for zero-copy buffer reuse. RegisterCodecV2 (line 63) panics at line 64-66 when codec == nil for the same reason RegisterCodec does: a nil CodecV2 would dereference during every RPC's (un)marshaling. If both a Codec and CodecV2 share a name, the V2 wins.","triggerScenarios":"Calling encoding.RegisterCodecV2(nil); registering a CodecV2 variable that was never initialized; passing the nil zero-value of a pointer-typed CodecV2 implementation.","commonSituations":"Migrating a custom codec from Codec to CodecV2 and forgetting to construct the new struct; conditional V2 registration where the construction path was skipped; refactor leaving a nil pointer before init().","solutions":["Construct the CodecV2 implementation before calling RegisterCodecV2.","Prefer registering a CodecV2 over a Codec for the same name only when the implementation is fully initialized.","Add a unit test that calls RegisterCodecV2 to surface a nil at test time, not in production init()."],"exampleFix":"// before\nvar c2 encoding.CodecV2\nfunc init() { encoding.RegisterCodecV2(c2) } // panic: nil\n\n// after\ntype protoCodecV2 struct{}\nfunc (protoCodecV2) Name() string                                { return \"proto\" }\nfunc (protoCodecV2) Marshal(v any) (mem.BufferSlice, error)      { /* ... */ return nil, nil }\nfunc (protoCodecV2) Unmarshal(d mem.BufferSlice, v any) error     { /* ... */ return nil }\nfunc init() { encoding.RegisterCodecV2(protoCodecV2{}) }","handlingStrategy":"validation","validationCode":"func registerV2Safe(c encoding.CodecV2) {\n    if c == nil {\n        log.Print(\"skipping V2 registration: nil codec\")\n        return\n    }\n    encoding.RegisterCodecV2(c)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Construct the CodecV2 implementation before calling RegisterCodecV2.","When migrating from Codec to CodecV2, build the new struct in the same init() that registers it.","Unit-test registration so a nil appears at test time."],"tags":["encoding","codecv2","registration","mem","panic","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}