Error Handling & Metadata

gRPC — Error Handling & Metadata
gRPC
Chapter 5 · Error Handling & Metadata

🚦 Error Handling & Metadata

Chapters 3–4 built calls that succeed. This chapter covers what happens when they don't, how to attach auxiliary data alongside a call without cramming it into the message itself, and how to stop a call from waiting forever.

gRPC Status Codes vs. HTTP Status Codes

gRPC has its own fixed enum of status codes, purpose-built for RPC semantics — distinct from HTTP's status codes, even though gRPC calls physically ride on top of HTTP/2.

HTTP Status Codes vs. gRPC Status Codes

HTTP

~40 general-purpose codes designed for web resources and REST conventions (404, 401, 500...).

gRPC

A fixed set of ~17 codes designed specifically for RPC outcomes — several (like DEADLINE_EXCEEDED or ALREADY_EXISTS) have no clean HTTP equivalent at all.

gRPC Status CodeMeaning
OKThe call succeeded
INVALID_ARGUMENTThe request itself was malformed
NOT_FOUNDThe requested resource doesn't exist
ALREADY_EXISTSAn attempt to create something that already exists
PERMISSION_DENIEDAuthenticated, but not authorized for this action
UNAUTHENTICATEDNo valid credentials were provided at all
DEADLINE_EXCEEDEDThe call didn't complete before its deadline
UNAVAILABLEThe service is temporarily unreachable — often safe to retry
INTERNALAn unexpected server-side error

Rich Error Details

Beyond a status code and a message, gRPC supports attaching structured error details via the google.rpc.Status extension mechanism — field-level validation errors, retry-after hints, or any custom structured data, all still strongly typed via Protobuf rather than the ad-hoc, differently-shaped error JSON bodies common across different REST APIs.

Metadata

Metadata is gRPC's equivalent of HTTP headers — key-value pairs sent alongside a call, outside the message body itself. Common uses: auth tokens (Chapter 7 covers this properly), request tracing IDs, and custom routing hints.

// Client: attaching metadata (an auth token, preview of Chapter 7) const metadata = new grpc.Metadata(); metadata.add('authorization', `Bearer ${token}`); client.getProduct({ id: 42 }, metadata, (err, response) => { ... });

Deadlines & Timeouts

Every gRPC call should carry a deadline — an absolute point in time by which the call must complete, after which it's automatically cancelled with DEADLINE_EXCEEDED. Deadlines are more powerful than a plain client-side timeout: they propagate across a chain of calls. If Service A calls Service B, which calls Service C, the same deadline can flow through all three — a slow Service C doesn't leave Service A waiting indefinitely, because the whole chain shares one clock, directly relevant to Chapter 8's microservices coverage.

// Client: a call with a 5-second deadline const deadline = Date.now() + 5000; client.getProduct({ id: 42 }, { deadline }, (err, response) => { if (err && err.code === grpc.status.DEADLINE_EXCEEDED) { // the call was cancelled — it never completed in time } });

💻 Coding Challenges

Challenge 1: Pick the Right Status Code

For each, name the correct gRPC status code: (a) a client requests a product ID that doesn't exist, (b) a client sends a request with no auth token at all, (c) a downstream service is temporarily down and the call couldn't be completed.

Goal: Practice matching a concrete failure to its specific gRPC status code, not just a generic "error."

→ Solution

Challenge 2: Explain Deadline Propagation

Service A calls Service B, which calls Service C. Explain, using this chapter's material, what deadline propagation buys this chain that a plain timeout set independently at each hop wouldn't.

Goal: Practice explaining why a shared deadline across a call chain is a genuine architectural advantage, not just a convenience.

→ Solution

Challenge 3: Metadata or Message Field?

For each, say whether it belongs in gRPC metadata or as a field in the request message: (a) an auth token, (b) the product ID being requested, (c) a request-tracing ID used for logging across services.

Goal: Practice distinguishing data that's genuinely part of the call's payload from auxiliary data that travels alongside it.

→ Solution

⚠️ Gotcha: An HTTP 200 Does Not Mean the gRPC Call Succeeded

Because gRPC rides on top of HTTP/2, a call's underlying HTTP status is very often 200 regardless of whether the gRPC call itself succeeded — the real outcome is communicated separately, via gRPC's own status field sent in an HTTP/2 trailer. Code that checks only the HTTP-level response (natural habit coming from REST) can easily miss a genuine NOT_FOUND or INTERNAL failure entirely. Always check the gRPC status specifically — generated client stubs surface this through the language's own error/exception mechanism (as in this chapter's err.code example), not through an HTTP status code. Relatedly, deadline propagation is typically opt-in per language/library, not automatic just because a deadline was set on the outermost call — check the specific gRPC library's documentation for how it actually threads a deadline through nested calls.

🎯 What's Next

The next chapter is Interceptors & Middleware — client/server interceptors for logging, auth, and retries, the gRPC equivalent of Express middleware.