grpc/grpc-go · critical

cannot register CodecV2 with empty string result for Name()

Error message

cannot register CodecV2 with empty string result for Name()

What it means

RegisterCodecV2 keys the codec by strings.ToLower(codec.Name()) exactly like RegisterCodec, so an empty Name() is rejected with a panic at encoding/encoding_v2.go:67-69. The name becomes the gRPC content-subtype and must be static.

Solutions

  1. Return a constant non-empty lowercase name from Name() (e.g. proto).
  2. Validate any config-derived name is non-empty before constructing/registering the codec.
  3. Keep the name identical across calls (it must be static).

Example fix

// before
func (c myCodecV2) Name() string { return c.name } // empty -> panic

// after
func (c myCodecV2) Name() string { return "myfmt" }
Defensive patterns

Strategy: validation

Validate before calling

func registerV2Safe(c encoding.CodecV2) {
    if c == nil || c.Name() == "" {
        log.Printf("skipping V2 registration: invalid name")
        return
    }
    encoding.RegisterCodecV2(c)
}

Prevention

When it happens

Trigger: A CodecV2 whose Name() returns an unset field, an empty config-derived value, or a stubbed empty string.

Common situations: Porting a Codec to CodecV2 and leaving Name() stubbed; name sourced from config/flag that is empty in the deployment; copy-paste without renaming.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/a4530a72e68fe881. Report an issue: GitHub.

Appendix: source

Thrown at encoding/encoding_v2.go:68

// should match the content-subtype of the encoding handled by the CodecV2.  This
// is case-insensitive, and is stored and looked up as lowercase.  If the
// result of calling Name() is an empty string, RegisterCodecV2 will panic. See
// Content-Type on
// https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md#requests for
// more details.
//
// If both a Codec and CodecV2 are registered with the same name, the CodecV2
// will be used.
//
// NOTE: this function must only be called during initialization time (i.e. in
// an init() function), and is not thread-safe.  If multiple Codecs are
// registered with the same name, the one registered last will take effect.
func RegisterCodecV2(codec CodecV2) {
	if codec == nil {
		panic("cannot register a nil CodecV2")
	}
	if codec.Name() == "" {
		panic("cannot register CodecV2 with empty string result for Name()")
	}
	contentSubtype := strings.ToLower(codec.Name())
	registeredCodecs[contentSubtype] = codec
}

// GetCodecV2 gets a registered CodecV2 by content-subtype, or nil if no CodecV2 is
// registered for the content-subtype.
//
// The content-subtype is expected to be lowercase.
func GetCodecV2(contentSubtype string) CodecV2 {
	c, _ := registeredCodecs[contentSubtype].(CodecV2)
	return c
}

View on GitHub (pinned to 0c51461d27)