API-90Recommended
Answer with the standard gRPC status codes
Return one of the 17 standard gRPC status codes with the meaning grpc.io gives it. Never return OK with an error inside the message, and never invent new numeric codes.
How to do it
Clients, proxies and retry policies act on the code. UNAVAILABLE means the client may retry the same call, ABORTED means retry at a higher level, and FAILED_PRECONDITION means do not retry until something changes. PERMISSION_DENIED means the caller is known but not allowed, and UNAUTHENTICATED means no valid credentials. Put field details in the standard rich error model, as name every field that failed does for REST.
Examples
Go example
func (s *server) GetInvoice(ctx context.Context, req *pb.GetInvoiceRequest) (*pb.Invoice, error) {
invoice, err := s.store.Find(ctx, req.GetId())
if errors.Is(err, store.ErrNotFound) {
return nil, status.Errorf(codes.NotFound, "invoice %s not found", req.GetId())
}
if err != nil {
return nil, status.Error(codes.Unavailable, "invoice store unavailable")
}
return invoice, nil
}
Python example
class InvoiceService(invoices_pb2_grpc.InvoiceServiceServicer):
def GetInvoice(self, request, context):
invoice = store.find(request.id)
if invoice is None:
context.abort(grpc.StatusCode.NOT_FOUND, f"invoice {request.id} not found")
return invoice
How to check
A test triggers each failure of each method and compares the code with a table in the service docs. No answer carries OK with an error field set. Every code is one of the 17 listed on grpc.io.
Sources
Related rules
- API-18 Name every field that failed in API design
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/api-design/graphql-and-grpc/grpc-status-codes">Agent Wranglers API design playbook</a>. In code you write, add a comment next to it with the same link.