In gRPC communication, a response reports an outcome through a predefined status code and may include an error message explaining the problem. Clients use the result to decide what happens next. section 5.3 section 5.3.1
Select a code that describes the failure rather than treating every unsuccessful call alike:
- Use OK for successful operations; use INVALID_ARGUMENT when the caller sends invalid input, such as an empty order ID. section 5.3.1
- Use CANCELLED when the client abandons a request, DEADLINE_EXCEEDED when its deadline expires, and NOT_FOUND when a resource is absent. section 5.3.1
- Use ALREADY_EXISTS for duplicate resources, PERMISSION_DENIED for insufficient access, RESOURCE_EXHAUSTED for quota limits, and INTERNAL for server errors. section 5.3.1
Status codes also drive resilience decisions. Retry transient outcomes such as Unavailable or ResourceExhausted, but do not retry validation failures. Combine retries with deadlines or timeouts, and use a circuit breaker to stop calls after repeated failures and resume them after recovery. section 6.4
Returning and reading validation errors
A server validates CreateOrderRequest fields, records BadRequest field violations, and returns the error. The Go client converts the response with status.Convert, inspects status details, and logs each invalid field and description. section 6.2.2
Listing 6.7 Server-client validation
...
import “google.golang.org/grpc/status"
func (s *server) Create(ctx context.Context, in *order.CreateOrderRequest)
(*order.CreateOrderResponse, error) {
var validationErrors []*errdetails.BadRequest_FieldViolation
if in.UserId < 1 { #1
validationErrors = append(validationErrors,
&errdetails.BadRequest_FieldViolation{
Field: "user_id",
Description: "user id cannot be less than 1",
}) #2
}
if in.ProductId < 0 { #3
validationErrors = append(validationErrors,
&errdetails.BadRequest_FieldViolation{
Field: "product_id",
Description: "product id cannot be negative",
}) #4
}
if len(validationErrors) > 0 {
stat := status.New(400, "invalid order request")
badRequest := &errdetails.BadRequest{} #5
badRequest.FieldViolations = validationErrors #6
s, _ := stat.WithDetails(badRequest) #7
return nil, s.Err()
}
return &order.CreateOrderResponse{OrderId: 1243}, nil
}
...
Shows Go server-side construction of structured BadRequest field violations for invalid user and product identifiers. section 6.2.2
...
import “google.golang.org/grpc/status"
orderResponse, errCreate := orderClient.Create(context.Background(),
&order.CreateOrderRequest{
UserId: -1,
ProductId: 0,
Price: 2,
})
if errCreate != nil {
stat := status.Convert(errCreate) #1
for _, detail := range stat.Details() {
switch errType := detail.(type) { #2
case *errdetails.BadRequest:
for _, violation := range errType.GetFieldViolations() {
log.Printf("The field %s has invalid value. desc: %v",
violation.GetField(), violation.GetDescription())
}
}
}
} else {
log.Printf("Order %d is created successfully.",
orderResponse.OrderId)
}
...
Shows Go client-side conversion of a gRPC error and iteration through field-level validation details. section 6.2.2










