0
# RPC Status and Error Handling
1
2
Standard error model and status codes for consistent error handling across gRPC services. Includes structured error details and context information for debugging and client error handling.
3
4
## Core Status Types
5
6
### Status
7
8
The canonical error model used across gRPC services.
9
10
```java { .api }
11
class Status {
12
int getCode();
13
String getMessage();
14
repeated Any getDetailsList();
15
16
static Status.Builder newBuilder();
17
Status.Builder toBuilder();
18
static Status parseFrom(byte[] data);
19
static Status parseFrom(InputStream input);
20
byte[] toByteArray();
21
}
22
23
interface StatusOrBuilder {
24
int getCode();
25
String getMessage();
26
java.util.List<com.google.protobuf.Any> getDetailsList();
27
int getDetailsCount();
28
com.google.protobuf.Any getDetails(int index);
29
}
30
```
31
32
### Code
33
34
Standard gRPC status codes indicating the error type.
35
36
```java { .api }
37
enum Code {
38
OK(0),
39
CANCELLED(1),
40
UNKNOWN(2),
41
INVALID_ARGUMENT(3),
42
DEADLINE_EXCEEDED(4),
43
NOT_FOUND(5),
44
ALREADY_EXISTS(6),
45
PERMISSION_DENIED(7),
46
RESOURCE_EXHAUSTED(8),
47
FAILED_PRECONDITION(9),
48
ABORTED(10),
49
OUT_OF_RANGE(11),
50
UNIMPLEMENTED(12),
51
INTERNAL(13),
52
UNAVAILABLE(14),
53
DATA_LOSS(15),
54
UNAUTHENTICATED(16);
55
56
int getNumber();
57
static Code forNumber(int value);
58
static Code valueOf(int value);
59
}
60
```
61
62
## Error Detail Types
63
64
### ErrorInfo
65
66
Structured error information with reason, domain, and metadata.
67
68
```java { .api }
69
class ErrorInfo {
70
String getReason();
71
String getDomain();
72
Struct getMetadata();
73
74
static ErrorInfo.Builder newBuilder();
75
}
76
```
77
78
### BadRequest
79
80
Details for field-level validation errors.
81
82
```java { .api }
83
class BadRequest {
84
repeated FieldViolation getFieldViolationsList();
85
86
static BadRequest.Builder newBuilder();
87
}
88
89
class BadRequest.FieldViolation {
90
String getField();
91
String getDescription();
92
93
static FieldViolation.Builder newBuilder();
94
}
95
```
96
97
### PreconditionFailure
98
99
Information about failed preconditions.
100
101
```java { .api }
102
class PreconditionFailure {
103
repeated Violation getViolationsList();
104
105
static PreconditionFailure.Builder newBuilder();
106
}
107
108
class PreconditionFailure.Violation {
109
String getType();
110
String getSubject();
111
String getDescription();
112
113
static Violation.Builder newBuilder();
114
}
115
```
116
117
### QuotaFailure
118
119
Details about quota violations.
120
121
```java { .api }
122
class QuotaFailure {
123
repeated Violation getViolationsList();
124
125
static QuotaFailure.Builder newBuilder();
126
}
127
128
class QuotaFailure.Violation {
129
String getSubject();
130
String getDescription();
131
132
static Violation.Builder newBuilder();
133
}
134
```
135
136
### RetryInfo
137
138
Information about retry timing for retryable errors.
139
140
```java { .api }
141
class RetryInfo {
142
Duration getRetryDelay();
143
144
static RetryInfo.Builder newBuilder();
145
}
146
```
147
148
### DebugInfo
149
150
Debug information for development and troubleshooting.
151
152
```java { .api }
153
class DebugInfo {
154
repeated String getStackEntriesList();
155
String getDetail();
156
157
static DebugInfo.Builder newBuilder();
158
}
159
```
160
161
### ResourceInfo
162
163
Information about the resource that caused the error.
164
165
```java { .api }
166
class ResourceInfo {
167
String getResourceType();
168
String getResourceName();
169
String getOwner();
170
String getDescription();
171
172
static ResourceInfo.Builder newBuilder();
173
}
174
```
175
176
### Help
177
178
Links and information for error resolution.
179
180
```java { .api }
181
class Help {
182
repeated Link getLinksList();
183
184
static Help.Builder newBuilder();
185
}
186
187
class Help.Link {
188
String getDescription();
189
String getUrl();
190
191
static Link.Builder newBuilder();
192
}
193
```
194
195
### LocalizedMessage
196
197
Localized error messages for user-facing errors.
198
199
```java { .api }
200
class LocalizedMessage {
201
String getLocale();
202
String getMessage();
203
204
static LocalizedMessage.Builder newBuilder();
205
}
206
```
207
208
## Context Information
209
210
### AttributeContext
211
212
Request context attributes for audit and debugging.
213
214
```java { .api }
215
class AttributeContext {
216
Request getRequest();
217
Response getResponse();
218
Resource getResource();
219
Peer getSource();
220
Peer getDestination();
221
222
static AttributeContext.Builder newBuilder();
223
}
224
225
class AttributeContext.Request {
226
String getId();
227
String getMethod();
228
Struct getHeaders();
229
String getPath();
230
String getHost();
231
String getScheme();
232
String getQuery();
233
Timestamp getTime();
234
long getSize();
235
String getProtocol();
236
String getReason();
237
Auth getAuth();
238
239
static Request.Builder newBuilder();
240
}
241
242
class AttributeContext.Response {
243
long getCode();
244
long getSize();
245
Struct getHeaders();
246
Timestamp getTime();
247
Duration getBackendLatency();
248
249
static Response.Builder newBuilder();
250
}
251
252
class AttributeContext.Peer {
253
String getIp();
254
long getPort();
255
Struct getLabels();
256
String getPrincipal();
257
String getRegionCode();
258
259
static Peer.Builder newBuilder();
260
}
261
```
262
263
## Usage Examples
264
265
### Creating Basic Status
266
267
```java
268
import com.google.rpc.Status;
269
import com.google.rpc.Code;
270
271
// Success status
272
Status success = Status.newBuilder()
273
.setCode(Code.OK.getNumber())
274
.setMessage("Operation completed successfully")
275
.build();
276
277
// Error status
278
Status error = Status.newBuilder()
279
.setCode(Code.INVALID_ARGUMENT.getNumber())
280
.setMessage("Invalid user ID provided")
281
.build();
282
```
283
284
### Creating Status with Error Details
285
286
```java
287
import com.google.rpc.BadRequest;
288
import com.google.rpc.ErrorInfo;
289
import com.google.protobuf.Any;
290
291
// Create field validation error
292
BadRequest.FieldViolation fieldError = BadRequest.FieldViolation.newBuilder()
293
.setField("email")
294
.setDescription("Invalid email format")
295
.build();
296
297
BadRequest badRequest = BadRequest.newBuilder()
298
.addFieldViolations(fieldError)
299
.build();
300
301
// Create error info
302
ErrorInfo errorInfo = ErrorInfo.newBuilder()
303
.setReason("INVALID_EMAIL_FORMAT")
304
.setDomain("myservice.googleapis.com")
305
.build();
306
307
// Pack details into Any messages
308
Any badRequestAny = Any.pack(badRequest);
309
Any errorInfoAny = Any.pack(errorInfo);
310
311
// Create status with details
312
Status detailedError = Status.newBuilder()
313
.setCode(Code.INVALID_ARGUMENT.getNumber())
314
.setMessage("Validation failed")
315
.addDetails(badRequestAny)
316
.addDetails(errorInfoAny)
317
.build();
318
```
319
320
### Handling Status Responses
321
322
```java
323
// Check if operation was successful
324
public void handleResponse(Status status) {
325
Code code = Code.forNumber(status.getCode());
326
327
switch (code) {
328
case OK:
329
System.out.println("Success: " + status.getMessage());
330
break;
331
332
case INVALID_ARGUMENT:
333
System.err.println("Invalid argument: " + status.getMessage());
334
handleValidationErrors(status.getDetailsList());
335
break;
336
337
case NOT_FOUND:
338
System.err.println("Resource not found: " + status.getMessage());
339
break;
340
341
case PERMISSION_DENIED:
342
System.err.println("Access denied: " + status.getMessage());
343
break;
344
345
case RESOURCE_EXHAUSTED:
346
System.err.println("Quota exceeded: " + status.getMessage());
347
handleRetry(status.getDetailsList());
348
break;
349
350
default:
351
System.err.println("Error " + code + ": " + status.getMessage());
352
}
353
}
354
355
private void handleValidationErrors(java.util.List<Any> details) {
356
for (Any detail : details) {
357
if (detail.is(BadRequest.class)) {
358
try {
359
BadRequest badRequest = detail.unpack(BadRequest.class);
360
for (BadRequest.FieldViolation violation : badRequest.getFieldViolationsList()) {
361
System.err.println("Field '" + violation.getField() + "': " + violation.getDescription());
362
}
363
} catch (InvalidProtocolBufferException e) {
364
System.err.println("Error unpacking BadRequest: " + e.getMessage());
365
}
366
}
367
}
368
}
369
370
private void handleRetry(java.util.List<Any> details) {
371
for (Any detail : details) {
372
if (detail.is(RetryInfo.class)) {
373
try {
374
RetryInfo retryInfo = detail.unpack(RetryInfo.class);
375
Duration delay = retryInfo.getRetryDelay();
376
long seconds = delay.getSeconds() + delay.getNanos() / 1_000_000_000L;
377
System.out.println("Retry after " + seconds + " seconds");
378
} catch (InvalidProtocolBufferException e) {
379
System.err.println("Error unpacking RetryInfo: " + e.getMessage());
380
}
381
}
382
}
383
}
384
```
385
386
### Exception Mapping
387
388
```java
389
import io.grpc.Status.Code as GrpcCode;
390
import io.grpc.StatusException;
391
392
// Convert between Proto Status and gRPC Status
393
public StatusException toGrpcException(com.google.rpc.Status protoStatus) {
394
GrpcCode grpcCode = GrpcCode.values()[protoStatus.getCode()];
395
io.grpc.Status grpcStatus = io.grpc.Status.fromCode(grpcCode)
396
.withDescription(protoStatus.getMessage());
397
398
return grpcStatus.asException();
399
}
400
401
// Create Proto Status from gRPC Status
402
public com.google.rpc.Status fromGrpcStatus(io.grpc.Status grpcStatus) {
403
return com.google.rpc.Status.newBuilder()
404
.setCode(grpcStatus.getCode().value())
405
.setMessage(grpcStatus.getDescription() != null ? grpcStatus.getDescription() : "")
406
.build();
407
}
408
```
409
410
## Common Status Code Usage
411
412
| Code | Usage | Retry? |
413
|------|-------|--------|
414
| `OK` | Success | No |
415
| `CANCELLED` | Request cancelled by client | No |
416
| `INVALID_ARGUMENT` | Invalid request parameters | No |
417
| `DEADLINE_EXCEEDED` | Request timeout | Yes |
418
| `NOT_FOUND` | Resource doesn't exist | No |
419
| `ALREADY_EXISTS` | Resource already exists | No |
420
| `PERMISSION_DENIED` | Access denied | No |
421
| `RESOURCE_EXHAUSTED` | Rate limited or quota exceeded | Yes |
422
| `FAILED_PRECONDITION` | System not in valid state | No |
423
| `UNAVAILABLE` | Service temporarily unavailable | Yes |
424
| `INTERNAL` | Internal server error | No |
425
| `UNAUTHENTICATED` | Authentication required | No |
426
427
## Best Practices
428
429
1. **Use appropriate status codes**: Choose the most specific code that describes the error condition
430
2. **Provide meaningful messages**: Include actionable information in the message field
431
3. **Add structured details**: Use typed error details for programmatic error handling
432
4. **Include context**: Add relevant context information for debugging
433
5. **Handle retryable errors**: Implement proper retry logic for transient failures
434
6. **Localize messages**: Use LocalizedMessage for user-facing errors