Handling gRPC error codes in Go primarily involves two packages: google.golang.org/grpc/status and google.golang.org/grpc/codes. Checking gRPC error codes is typically done to handle different error types appropriately. The following provides a detailed step-by-step explanation and example:
Step 1: Check for Errors
When you receive an error from a gRPC call, first verify if it is nil. If not, handle the error further.
goresp, err := client.SomeRPCMethod(ctx, req) if err != nil { // Handle the error }
Step 2: Check the Error Type
Use the FromError function from the status package to convert the error into a *status.Status, enabling you to retrieve specific details such as the error code and message.
gost, ok := status.FromError(err) if !ok { // The error is not a *status.Status type; it may be another error type return fmt.Errorf("unexpected error type: %v", err) }
Step 3: Retrieve and Check the Error Code
Retrieve the error code using st.Code() and match it against different error codes using a conditional statement. The codes package contains all standard gRPC error codes.
goswitch st.Code() { case codes.NotFound: // Handle the not-found case fmt.Println("Resource not found:", st.Message()) case codes.PermissionDenied: // Handle the permission-denied case fmt.Println("Permission denied:", st.Message()) default: // Handle other error types fmt.Println("Other error:", st.Message()) }
Example
Combining the above steps, the following is a complete example that simulates a client calling a gRPC service and handling errors based on the returned error types.
gopackage main import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func main() { conn, err := grpc.Dial("your-grpc-server-address", grpc.WithInsecure()) if err != nil { panic(err) } defer conn.Close() client := NewYourClientServiceClient(conn) req := &YourRequest{} // Assuming `YourRequest` is the gRPC request type ctx := context.Background() resp, err := client.YourMethod(ctx, req) if err != nil { st, ok := status.FromError(err) if !ok { fmt.Printf("Non-gRPC error: %v\n", err) return } switch st.Code() { case codes.NotFound: fmt.Println("Resource not found:", st.Message()) case codes.PermissionDenied: fmt.Println("Permission denied:", st.Message()) default: fmt.Println("Other error:", st.Message()) } return } fmt.Println("Response:", resp) }
In this example, we first establish a connection with the gRPC service, then send a request. If an error occurs, we verify it is a *status.Status error, retrieve the error code, and handle different error types accordingly. This approach ensures error handling is clear and organized.