Custom errors in gRPC

Custom Errors in gRPC

When a gRPC client receives an application error, it only contains a string and nothing else. Here’s something I did to pass additional error information using gRPC status system.

First, looking at the gRPC implementation, you can see that if an error type has GRPCStatus *status.Status method, then the gRPC implementation gets the status information from this method instead of generating one of it own, using err.Error(). So, in your custom error types simply implement this method to encode diagnostic information so the receiving end can decode it. I chose to pass a JSON-marshaled string:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func (e MyError) GRPCStatus() *status.Status {
  var code codes.Code
  switch e.HTTPStatus {
    case http.StatusBadRequest:
      code = codes.InvalidArgument
    case http.StatusUnauthorized:
       code = codes.Unauthenticated
    default:
       code = codes.Unknown
   }
   x, _ := json.Marshal(e)
   return status.New(code, string(x))
}

In this example, the error type includes an HTTP status code, and the gRPC status is decided based on that.

On the receiving end, I have this function:

1
2
3
4
5
6
7
8
9
func FromGRPCError(err error) (MyError, bool) {
  if x, ok := status.FromError(err); ok {
    var e MyError
    if json.Unmarshal([]byte(x.Message()), &e) == nil {
    return e, true
   }
  }
  return MyError{}, false
}

This decodes the error information from the incoming error.