micro/go-micro · error
unsupported Content-Type
Error message
unsupported Content-Type
What it means
The go-micro gRPC codec can only decode message bodies for a fixed set of content types: application/grpc+json, application/grpc+proto, and application/grpc. ReadBody decodes the length-prefixed frame from the connection and then switches on the codec's stored ContentType; any other content type falls through to this error, leaving the body undecoded.
Source
Thrown at codec/grpc/grpc.go:67
func (c *Codec) ReadBody(b interface{}) error {
// no body
if b == nil {
return nil
}
_, buf, err := decode(c.Conn)
if err != nil {
return err
}
switch c.ContentType {
case "application/grpc+json":
return json.Unmarshal(buf, b)
case "application/grpc+proto", "application/grpc":
return proto.Unmarshal(buf, b.(proto.Message))
}
return errors.New("unsupported Content-Type")
}
func (c *Codec) Write(m *codec.Message, b interface{}) error {
var buf []byte
var err error
if ct := m.Header["Content-Type"]; len(ct) > 0 {
c.ContentType = ct
}
if ct := m.Header["content-type"]; len(ct) > 0 {
c.ContentType = ct
}
switch m.Type {
case codec.Request:
parts := strings.Split(m.Endpoint, ".")
m.Header[":method"] = "POST"View on GitHub (pinned to 24529f1404)
Solutions
- Set the request/response content-type to exactly "application/grpc+proto", "application/grpc", or "application/grpc+json" on both client and server.
- Strip any media-type parameters (charset etc.) or normalize the content-type before it reaches the codec.
- If you need another format, register/use a codec that supports it instead of the gRPC codec.
- Align codec configuration between client and server so both negotiate the same content type.
Example fix
// before
req.Header.Set("Content-Type", "application/grpc+protobuf")
// after
req.Header.Set("Content-Type", "application/grpc+proto") Defensive patterns
Strategy: validation
Validate before calling
ct := header.Get("Content-Type")
base := strings.TrimSpace(strings.Split(ct, ";")[0])
switch base {
case "application/grpc+json", "application/grpc+proto", "application/grpc":
// ok
default:
return fmt.Errorf("content-type %q not supported by grpc codec", ct)
} Type guard
func supportedCT(ct string) bool {
switch strings.TrimSpace(strings.Split(ct, ";")[0]) {
case "application/grpc+json", "application/grpc+proto", "application/grpc":
return true
}
return false
} Prevention
- Hardcode one of the three supported content types in client setup.
- Normalize content-type (strip charset params, lowercase) in middleware.
- Keep codec configuration symmetric between client and server.
- Integration-test with a real gRPC client to catch header drift.
When it happens
Trigger: ReadBody is called after ReadHeader stored a ContentType that is not one of the three supported values — e.g. a request with "content-type: application/grpc+protobuf" (misspelled), "text/plain", "application/json" (without the grpc prefix), or an empty content-type header on the incoming stream.
Common situations: A client library or proxy sends a content-type that differs slightly from what go-micro expects (e.g. application/grpc-web, or a charset suffix like "application/grpc+proto; charset=utf-8"); a custom codec was registered on one side but not the other; tests forget to set the content-type header.
Related errors
- unknown request path
- unsupported Content-Type: %s
- ErrInvalidMessage
- failed to marshal: %v is not type of *bytes.Frame or proto.M
- failed to unmarshal: %v is not type of proto.Message
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/ce488564f064929a.
Report an issue: GitHub.