Consistent status codes drive retries, alerts and client behaviour.
Every gRPC call ends with a status: a code plus an optional message (details in grpc-js). There are 17 codes; the ones you will use most:
OK(0): success.INVALID_ARGUMENT(3): the request is malformed regardless of system state.NOT_FOUND(5),ALREADY_EXISTS(6).PERMISSION_DENIED(7) versusUNAUTHENTICATED(16): authenticated but not allowed, versus no valid credentials.FAILED_PRECONDITION(9): the system is not in the required state (e.g. deleting a non-empty folder).RESOURCE_EXHAUSTED(8): quota or rate limit.DEADLINE_EXCEEDED(4),CANCELLED(1).UNAVAILABLE(14): transient, usually safe to retry with backoff.INTERNAL(13) andUNKNOWN(2): bugs; an uncaught exception in a handler becomesUNKNOWN.
In grpc-js, servers fail a call by passing an error object to the callback: { code: grpc.status.NOT_FOUND, details: "no such user" }. Clients receive an Error with code, details and metadata.
Branch on the code, not on message text. For structured, machine-readable details (which field was invalid, retry delay), Google's richer error model packs a google.rpc.Status with typed details into the grpc-status-details-bin trailer.
Example
import * as grpc from "@grpc/grpc-js";
import * as protoLoader from "@grpc/proto-loader";
const { hello } = grpc.loadPackageDefinition(protoLoader.loadSync("hello.proto"));
const server = new grpc.Server();
server.addService(hello.v1.Greeter.service, {
SayHello: ({ request }, callback) => {
if (!request.name) {
return callback({ code: grpc.status.INVALID_ARGUMENT, details: "name is required" });
}
callback(null, { message: `Hello, ${request.name}` });
},
});
server.bindAsync("127.0.0.1:50052", grpc.ServerCredentials.createInsecure(), () => {
const client = new hello.v1.Greeter("127.0.0.1:50052", grpc.credentials.createInsecure());
client.SayHello({ name: "" }, (err) => {
console.log(err.code, grpc.status[err.code], err.details);
// 3 INVALID_ARGUMENT name is required
server.forceShutdown();
});
});Remember
- Every call ends with a status code and message
- UNAUTHENTICATED = no credentials; PERMISSION_DENIED = not allowed
- UNAVAILABLE is the typical retryable code
- Branch on codes, never on message strings
Watch out for
- Returning INTERNAL or UNKNOWN for client mistakes, which hides bugs and triggers wrong alerts.