Status codes and errors

gRPC · Essentials · 10 min

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) versus UNAUTHENTICATED (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) and UNKNOWN (2): bugs; an uncaught exception in a handler becomes UNKNOWN.

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.

Check yourself

  1. A valid token calls an admin-only method without the admin role. Which code fits?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: grpc.io/docs/guides/status-codes/