0
# Error Handling
1
2
Comprehensive error types and utilities for different failure scenarios in Temporal operations, enabling robust error handling and debugging.
3
4
## Capabilities
5
6
### Core Error Classes
7
8
Primary error classes for different types of failures in Temporal operations.
9
10
```typescript { .api }
11
/**
12
* Generic service error for gRPC operations
13
*/
14
class ServiceError extends Error {
15
/** gRPC status code */
16
readonly code: Status;
17
/** Detailed error message */
18
readonly details: string;
19
20
constructor(code: Status, details: string, message?: string);
21
}
22
23
/**
24
* Workflow execution failed error
25
*/
26
class WorkflowFailedError extends Error {
27
/** The failure that caused workflow to fail */
28
readonly cause: TemporalFailure;
29
/** Workflow identifier */
30
readonly workflowId: string;
31
/** Workflow type name */
32
readonly workflowType: string;
33
/** Workflow run identifier */
34
readonly runId: string;
35
36
constructor(
37
cause: TemporalFailure,
38
workflowId: string,
39
workflowType: string,
40
runId: string
41
);
42
}
43
44
/**
45
* Workflow update operation failed error
46
*/
47
class WorkflowUpdateFailedError extends Error {
48
/** The failure that caused update to fail */
49
readonly cause: TemporalFailure;
50
/** Workflow identifier */
51
readonly workflowId: string;
52
/** Workflow run identifier */
53
readonly runId: string;
54
/** Update identifier */
55
readonly updateId: string;
56
57
constructor(
58
cause: TemporalFailure,
59
workflowId: string,
60
runId: string,
61
updateId: string
62
);
63
}
64
65
/**
66
* Workflow update RPC timeout or cancellation error
67
*/
68
class WorkflowUpdateRPCTimeoutOrCancelledError extends Error {
69
/** Workflow identifier */
70
readonly workflowId: string;
71
/** Workflow run identifier */
72
readonly runId: string;
73
/** Update identifier */
74
readonly updateId: string;
75
76
constructor(workflowId: string, runId: string, updateId: string);
77
}
78
79
/**
80
* Workflow continued as new error (not always a failure)
81
*/
82
class WorkflowContinuedAsNewError extends Error {
83
/** New workflow execution info */
84
readonly newExecution: WorkflowExecution;
85
86
constructor(newExecution: WorkflowExecution);
87
}
88
```
89
90
**Usage Examples:**
91
92
```typescript
93
import {
94
WorkflowFailedError,
95
ServiceError,
96
isGrpcServiceError
97
} from "@temporalio/client";
98
99
try {
100
const result = await client.workflow.execute('myWorkflow', {
101
args: ['arg1'],
102
taskQueue: 'my-queue',
103
workflowId: 'workflow-1',
104
});
105
} catch (error) {
106
if (error instanceof WorkflowFailedError) {
107
console.log(`Workflow ${error.workflowId} failed:`, error.cause);
108
109
// Handle specific failure types
110
if (error.cause instanceof ApplicationFailure) {
111
console.log('Application error:', error.cause.message);
112
} else if (error.cause instanceof TimeoutFailure) {
113
console.log('Workflow timed out:', error.cause.timeoutType);
114
}
115
} else if (isGrpcServiceError(error)) {
116
console.log('gRPC error:', error.code, error.details);
117
}
118
}
119
```
120
121
### Error Utility Functions
122
123
Utility functions for identifying and handling different types of errors.
124
125
```typescript { .api }
126
/**
127
* Check if error is gRPC service error
128
*/
129
function isGrpcServiceError(error: unknown): error is ServiceError;
130
131
/**
132
* Check if error is gRPC deadline exceeded
133
*/
134
function isGrpcDeadlineError(error: unknown): boolean;
135
136
/**
137
* Check if error is gRPC cancelled
138
*/
139
function isGrpcCancelledError(error: unknown): boolean;
140
```
141
142
**Usage Examples:**
143
144
```typescript
145
import {
146
isGrpcServiceError,
147
isGrpcDeadlineError,
148
isGrpcCancelledError
149
} from "@temporalio/client";
150
151
try {
152
await someTemporalOperation();
153
} catch (error) {
154
if (isGrpcDeadlineError(error)) {
155
console.log('Request timed out, retrying with longer deadline...');
156
// Retry logic
157
} else if (isGrpcCancelledError(error)) {
158
console.log('Request was cancelled');
159
// Handle cancellation
160
} else if (isGrpcServiceError(error)) {
161
console.log(`gRPC error [${error.code}]: ${error.details}`);
162
// Handle specific gRPC errors
163
}
164
}
165
```
166
167
### Schedule-Specific Errors
168
169
Error types specific to schedule operations.
170
171
```typescript { .api }
172
/**
173
* Schedule already exists and is running
174
*/
175
class ScheduleAlreadyRunning extends Error {
176
readonly scheduleId: string;
177
178
constructor(scheduleId: string) {
179
super(`Schedule '${scheduleId}' already exists and is running`);
180
this.scheduleId = scheduleId;
181
}
182
}
183
184
/**
185
* Schedule not found error
186
*/
187
class ScheduleNotFoundError extends Error {
188
readonly scheduleId: string;
189
190
constructor(scheduleId: string) {
191
super(`Schedule '${scheduleId}' not found`);
192
this.scheduleId = scheduleId;
193
}
194
}
195
```
196
197
**Usage Examples:**
198
199
```typescript
200
import { ScheduleAlreadyRunning, ScheduleNotFoundError } from "@temporalio/client";
201
202
try {
203
await scheduleClient.create({
204
scheduleId: 'daily-backup',
205
// ... other options
206
});
207
} catch (error) {
208
if (error instanceof ScheduleAlreadyRunning) {
209
console.log(`Schedule ${error.scheduleId} already exists, updating instead...`);
210
const handle = scheduleClient.getHandle(error.scheduleId);
211
await handle.update({
212
// ... update options
213
});
214
}
215
}
216
217
try {
218
const handle = scheduleClient.getHandle('non-existent-schedule');
219
await handle.describe();
220
} catch (error) {
221
if (error instanceof ScheduleNotFoundError) {
222
console.log(`Schedule ${error.scheduleId} does not exist`);
223
}
224
}
225
```
226
227
### Activity Completion Errors
228
229
Error types for activity completion operations.
230
231
```typescript { .api }
232
/**
233
* Activity not found error
234
*/
235
class ActivityNotFoundError extends Error {
236
constructor(message: string);
237
}
238
239
/**
240
* Activity completion failed error
241
*/
242
class ActivityCompletionError extends Error {
243
readonly cause?: Error;
244
245
constructor(message: string, cause?: Error);
246
}
247
248
/**
249
* Activity was cancelled error
250
*/
251
class ActivityCancelledError extends Error {
252
readonly details?: unknown;
253
254
constructor(message: string, details?: unknown);
255
}
256
257
/**
258
* Activity was paused error
259
*/
260
class ActivityPausedError extends Error {
261
constructor(message: string);
262
}
263
```
264
265
**Usage Examples:**
266
267
```typescript
268
import {
269
ActivityNotFoundError,
270
ActivityCompletionError,
271
ActivityCancelledError
272
} from "@temporalio/client";
273
274
try {
275
await activityClient.complete(taskToken, result);
276
} catch (error) {
277
if (error instanceof ActivityNotFoundError) {
278
console.log('Activity not found, may have already completed or timed out');
279
} else if (error instanceof ActivityCancelledError) {
280
console.log('Activity was cancelled:', error.details);
281
} else if (error instanceof ActivityCompletionError) {
282
console.log('Failed to complete activity:', error.message);
283
if (error.cause) {
284
console.log('Underlying cause:', error.cause);
285
}
286
}
287
}
288
```
289
290
### Workflow Query Errors
291
292
Error types for workflow query operations.
293
294
```typescript { .api }
295
/**
296
* Query was rejected by workflow
297
*/
298
class QueryRejectedError extends Error {
299
readonly queryType: string;
300
readonly workflowId: string;
301
readonly runId: string;
302
303
constructor(queryType: string, workflowId: string, runId: string, message: string);
304
}
305
306
/**
307
* Query not registered on workflow
308
*/
309
class QueryNotRegisteredError extends Error {
310
readonly queryType: string;
311
readonly workflowId: string;
312
readonly runId: string;
313
314
constructor(queryType: string, workflowId: string, runId: string);
315
}
316
```
317
318
**Usage Examples:**
319
320
```typescript
321
import { QueryRejectedError, QueryNotRegisteredError } from "@temporalio/client";
322
323
try {
324
const status = await workflowHandle.query('getStatus');
325
} catch (error) {
326
if (error instanceof QueryRejectedError) {
327
console.log(`Query '${error.queryType}' was rejected by workflow ${error.workflowId}`);
328
} else if (error instanceof QueryNotRegisteredError) {
329
console.log(`Query '${error.queryType}' is not registered on workflow ${error.workflowId}`);
330
}
331
}
332
```
333
334
### Task Queue Errors
335
336
Error types for task queue operations.
337
338
```typescript { .api }
339
/**
340
* Build ID not found error
341
*/
342
class BuildIdNotFoundError extends Error {
343
readonly buildId: string;
344
readonly taskQueue: string;
345
346
constructor(buildId: string, taskQueue: string);
347
}
348
```
349
350
**Usage Examples:**
351
352
```typescript
353
import { BuildIdNotFoundError } from "@temporalio/client";
354
355
try {
356
await taskQueueClient.updateBuildIdCompatibility('my-queue', {
357
operation: 'promoteBuildIdWithinSet',
358
buildId: 'non-existent-build-id',
359
});
360
} catch (error) {
361
if (error instanceof BuildIdNotFoundError) {
362
console.log(`Build ID ${error.buildId} not found in task queue ${error.taskQueue}`);
363
}
364
}
365
```
366
367
## Error Handling Patterns
368
369
### Retry Logic with Error Classification
370
371
```typescript
372
class TemporalErrorHandler {
373
async executeWithRetry<T>(
374
operation: () => Promise<T>,
375
maxRetries: number = 3,
376
baseDelay: number = 1000
377
): Promise<T> {
378
let lastError: Error;
379
380
for (let attempt = 0; attempt <= maxRetries; attempt++) {
381
try {
382
return await operation();
383
} catch (error) {
384
lastError = error as Error;
385
386
// Don't retry on certain error types
387
if (
388
error instanceof WorkflowFailedError ||
389
error instanceof ActivityCancelledError ||
390
error instanceof QueryRejectedError
391
) {
392
throw error;
393
}
394
395
// Retry on transient errors
396
if (
397
isGrpcDeadlineError(error) ||
398
isGrpcServiceError(error) ||
399
error instanceof ActivityNotFoundError
400
) {
401
if (attempt < maxRetries) {
402
const delay = baseDelay * Math.pow(2, attempt); // Exponential backoff
403
console.log(`Attempt ${attempt + 1} failed, retrying in ${delay}ms...`);
404
await new Promise(resolve => setTimeout(resolve, delay));
405
continue;
406
}
407
}
408
409
throw error;
410
}
411
}
412
413
throw lastError!;
414
}
415
}
416
417
// Usage
418
const errorHandler = new TemporalErrorHandler();
419
420
const result = await errorHandler.executeWithRetry(async () => {
421
return await client.workflow.execute('unreliableWorkflow', {
422
args: ['data'],
423
taskQueue: 'my-queue',
424
workflowId: 'workflow-' + Date.now(),
425
});
426
});
427
```
428
429
### Comprehensive Error Logging
430
431
```typescript
432
class ErrorLogger {
433
logTemporalError(error: Error, context: string) {
434
const baseInfo = {
435
timestamp: new Date().toISOString(),
436
context,
437
errorType: error.constructor.name,
438
message: error.message,
439
};
440
441
if (error instanceof WorkflowFailedError) {
442
console.error('Workflow failed:', {
443
...baseInfo,
444
workflowId: error.workflowId,
445
workflowType: error.workflowType,
446
runId: error.runId,
447
cause: {
448
type: error.cause.constructor.name,
449
message: error.cause.message,
450
},
451
});
452
} else if (error instanceof ServiceError) {
453
console.error('Service error:', {
454
...baseInfo,
455
grpcCode: error.code,
456
details: error.details,
457
});
458
} else if (error instanceof ScheduleNotFoundError) {
459
console.error('Schedule error:', {
460
...baseInfo,
461
scheduleId: error.scheduleId,
462
});
463
} else {
464
console.error('General error:', baseInfo);
465
}
466
}
467
}
468
469
// Usage
470
const logger = new ErrorLogger();
471
472
try {
473
await someTemporalOperation();
474
} catch (error) {
475
logger.logTemporalError(error as Error, 'workflow execution');
476
throw error;
477
}
478
```