0
# Error Handling
1
2
Comprehensive error classes for different types of HTTP client failures with detailed error information and proper error handling patterns.
3
4
## Capabilities
5
6
### Error Classes
7
8
Undici provides specific error types for different failure scenarios to enable precise error handling.
9
10
```javascript { .api }
11
/**
12
* All undici error types
13
*/
14
const errors: {
15
UndiciError: typeof UndiciError;
16
ConnectTimeoutError: typeof ConnectTimeoutError;
17
HeadersTimeoutError: typeof HeadersTimeoutError;
18
BodyTimeoutError: typeof BodyTimeoutError;
19
ResponseError: typeof ResponseError;
20
ResponseStatusCodeError: typeof ResponseStatusCodeError;
21
RequestRetryError: typeof RequestRetryError;
22
ClientDestroyedError: typeof ClientDestroyedError;
23
ClientClosedError: typeof ClientClosedError;
24
SocketError: typeof SocketError;
25
NotSupportedError: typeof NotSupportedError;
26
InvalidArgumentError: typeof InvalidArgumentError;
27
InvalidReturnValueError: typeof InvalidReturnValueError;
28
RequestAbortedError: typeof RequestAbortedError;
29
InformationalError: typeof InformationalError;
30
RequestContentLengthMismatchError: typeof RequestContentLengthMismatchError;
31
ResponseContentLengthMismatchError: typeof ResponseContentLengthMismatchError;
32
HeadersOverflowError: typeof HeadersOverflowError;
33
HTTPParserError: typeof HTTPParserError;
34
};
35
```
36
37
### Base Error Class
38
39
```javascript { .api }
40
/**
41
* Base class for all undici errors
42
*/
43
class UndiciError extends Error {
44
name: string;
45
code: string;
46
message: string;
47
}
48
```
49
50
### Network Timeout Errors
51
52
Errors related to network timeouts during different phases of the request.
53
54
```javascript { .api }
55
/**
56
* Connection establishment timeout
57
*/
58
class ConnectTimeoutError extends UndiciError {
59
name: 'ConnectTimeoutError';
60
code: 'UND_ERR_CONNECT_TIMEOUT';
61
message: string;
62
}
63
64
/**
65
* Headers reception timeout
66
*/
67
class HeadersTimeoutError extends UndiciError {
68
name: 'HeadersTimeoutError';
69
code: 'UND_ERR_HEADERS_TIMEOUT';
70
message: string;
71
}
72
73
/**
74
* Body reception timeout
75
*/
76
class BodyTimeoutError extends UndiciError {
77
name: 'BodyTimeoutError';
78
code: 'UND_ERR_BODY_TIMEOUT';
79
message: string;
80
}
81
```
82
83
**Usage Examples:**
84
85
```javascript
86
import { request, errors } from 'undici';
87
88
try {
89
const response = await request('https://slow-server.example.com/data', {
90
headersTimeout: 5000, // 5 second headers timeout
91
bodyTimeout: 10000 // 10 second body timeout
92
});
93
} catch (error) {
94
if (error instanceof errors.ConnectTimeoutError) {
95
console.log('Failed to establish connection within timeout');
96
} else if (error instanceof errors.HeadersTimeoutError) {
97
console.log('Headers not received within timeout');
98
} else if (error instanceof errors.BodyTimeoutError) {
99
console.log('Response body not received within timeout');
100
}
101
}
102
```
103
104
### HTTP Response Errors
105
106
Errors related to HTTP response processing and status codes.
107
108
```javascript { .api }
109
/**
110
* General HTTP response error
111
*/
112
class ResponseError extends UndiciError {
113
name: 'ResponseError';
114
code: 'UND_ERR_RESPONSE';
115
statusCode: number;
116
headers: Record<string, string | string[]>;
117
body: any;
118
}
119
120
/**
121
* HTTP status code error
122
*/
123
class ResponseStatusCodeError extends UndiciError {
124
name: 'ResponseStatusCodeError';
125
code: 'UND_ERR_RESPONSE_STATUS_CODE';
126
statusCode: number;
127
headers: Record<string, string | string[]>;
128
body: any;
129
}
130
131
/**
132
* Request retry error after exhausting retries
133
*/
134
class RequestRetryError extends UndiciError {
135
name: 'RequestRetryError';
136
code: 'UND_ERR_REQ_RETRY';
137
statusCode?: number;
138
data: {
139
count: number;
140
error: Error;
141
};
142
}
143
```
144
145
**Usage Examples:**
146
147
```javascript
148
import { request, errors } from 'undici';
149
150
try {
151
const response = await request('https://api.example.com/protected', {
152
method: 'GET',
153
throwOnError: true
154
});
155
} catch (error) {
156
if (error instanceof errors.ResponseStatusCodeError) {
157
console.log(`HTTP ${error.statusCode}: ${error.message}`);
158
console.log('Response headers:', error.headers);
159
console.log('Response body:', error.body);
160
161
// Handle specific status codes
162
if (error.statusCode === 401) {
163
console.log('Authentication required');
164
} else if (error.statusCode === 403) {
165
console.log('Access forbidden');
166
} else if (error.statusCode >= 500) {
167
console.log('Server error occurred');
168
}
169
} else if (error instanceof errors.RequestRetryError) {
170
console.log(`Request failed after ${error.data.count} retries`);
171
console.log('Original error:', error.data.error.message);
172
}
173
}
174
```
175
176
### Client State Errors
177
178
Errors related to client lifecycle and state management.
179
180
```javascript { .api }
181
/**
182
* Using destroyed client
183
*/
184
class ClientDestroyedError extends UndiciError {
185
name: 'ClientDestroyedError';
186
code: 'UND_ERR_DESTROYED';
187
message: 'The client is destroyed';
188
}
189
190
/**
191
* Using closed client
192
*/
193
class ClientClosedError extends UndiciError {
194
name: 'ClientClosedError';
195
code: 'UND_ERR_CLOSED';
196
message: 'The client is closed';
197
}
198
199
/**
200
* Request aborted by user
201
*/
202
class RequestAbortedError extends UndiciError {
203
name: 'RequestAbortedError';
204
code: 'UND_ERR_ABORTED';
205
message: 'Request aborted';
206
}
207
```
208
209
**Usage Examples:**
210
211
```javascript
212
import { Client, errors } from 'undici';
213
214
const client = new Client('https://api.example.com');
215
216
// Destroy client
217
await client.destroy();
218
219
try {
220
// This will throw ClientDestroyedError
221
await client.request({ path: '/data' });
222
} catch (error) {
223
if (error instanceof errors.ClientDestroyedError) {
224
console.log('Cannot use destroyed client');
225
}
226
}
227
228
// Abort request example
229
const controller = new AbortController();
230
231
// Abort after 2 seconds
232
setTimeout(() => controller.abort(), 2000);
233
234
try {
235
const response = await client.request({
236
path: '/slow-endpoint',
237
signal: controller.signal
238
});
239
} catch (error) {
240
if (error instanceof errors.RequestAbortedError) {
241
console.log('Request was aborted');
242
}
243
}
244
```
245
246
### Protocol and Parsing Errors
247
248
Errors related to HTTP protocol violations and parsing failures.
249
250
```javascript { .api }
251
/**
252
* Low-level socket errors
253
*/
254
class SocketError extends UndiciError {
255
name: 'SocketError';
256
code: 'UND_ERR_SOCKET';
257
socket: {
258
localAddress: string;
259
localPort: number;
260
remoteAddress: string;
261
remotePort: number;
262
};
263
}
264
265
/**
266
* Headers size exceeds limits
267
*/
268
class HeadersOverflowError extends UndiciError {
269
name: 'HeadersOverflowError';
270
code: 'UND_ERR_HEADERS_OVERFLOW';
271
message: 'Headers overflow';
272
}
273
274
/**
275
* Request body length mismatch
276
*/
277
class RequestContentLengthMismatchError extends UndiciError {
278
name: 'RequestContentLengthMismatchError';
279
code: 'UND_ERR_REQ_CONTENT_LENGTH_MISMATCH';
280
message: 'Request body length does not match content-length header';
281
}
282
283
/**
284
* Response body length mismatch
285
*/
286
class ResponseContentLengthMismatchError extends UndiciError {
287
name: 'ResponseContentLengthMismatchError';
288
code: 'UND_ERR_RES_CONTENT_LENGTH_MISMATCH';
289
message: 'Response body length does not match content-length header';
290
}
291
292
/**
293
* HTTP parsing errors
294
*/
295
class HTTPParserError extends Error {
296
name: 'HTTPParserError';
297
code: string;
298
bytesParsed: number;
299
}
300
```
301
302
**Usage Examples:**
303
304
```javascript
305
import { request, errors } from 'undici';
306
307
try {
308
const response = await request('https://malformed-server.example.com/data');
309
} catch (error) {
310
if (error instanceof errors.HTTPParserError) {
311
console.log('HTTP parsing failed:', error.message);
312
console.log('Bytes parsed:', error.bytesParsed);
313
} else if (error instanceof errors.HeadersOverflowError) {
314
console.log('Response headers too large');
315
} else if (error instanceof errors.ResponseContentLengthMismatchError) {
316
console.log('Response body length mismatch');
317
} else if (error instanceof errors.SocketError) {
318
console.log('Socket error:', error.message);
319
console.log('Socket info:', error.socket);
320
}
321
}
322
```
323
324
### Validation Errors
325
326
Errors related to invalid arguments and return values.
327
328
```javascript { .api }
329
/**
330
* Invalid function arguments
331
*/
332
class InvalidArgumentError extends UndiciError {
333
name: 'InvalidArgumentError';
334
code: 'UND_ERR_INVALID_ARG';
335
message: string;
336
}
337
338
/**
339
* Invalid return values
340
*/
341
class InvalidReturnValueError extends UndiciError {
342
name: 'InvalidReturnValueError';
343
code: 'UND_ERR_INVALID_RETURN_VALUE';
344
message: string;
345
}
346
347
/**
348
* Unsupported functionality
349
*/
350
class NotSupportedError extends UndiciError {
351
name: 'NotSupportedError';
352
code: 'UND_ERR_NOT_SUPPORTED';
353
message: string;
354
}
355
```
356
357
**Usage Examples:**
358
359
```javascript
360
import { request, errors } from 'undici';
361
362
try {
363
// Invalid URL will throw InvalidArgumentError
364
await request(null);
365
} catch (error) {
366
if (error instanceof errors.InvalidArgumentError) {
367
console.log('Invalid argument provided:', error.message);
368
}
369
}
370
371
try {
372
// Unsupported feature
373
await request('https://api.example.com', {
374
method: 'INVALID_METHOD'
375
});
376
} catch (error) {
377
if (error instanceof errors.NotSupportedError) {
378
console.log('Feature not supported:', error.message);
379
}
380
}
381
```
382
383
## Error Handling Patterns
384
385
### Comprehensive Error Handling
386
387
```javascript
388
import { request, errors } from 'undici';
389
390
async function safeRequest(url, options = {}) {
391
try {
392
return await request(url, {
393
...options,
394
headersTimeout: 10000,
395
bodyTimeout: 30000,
396
throwOnError: true
397
});
398
} catch (error) {
399
// Network and timeout errors
400
if (error instanceof errors.ConnectTimeoutError) {
401
throw new Error('Connection timeout - server may be down');
402
}
403
404
if (error instanceof errors.HeadersTimeoutError) {
405
throw new Error('Headers timeout - server may be overloaded');
406
}
407
408
if (error instanceof errors.BodyTimeoutError) {
409
throw new Error('Body timeout - response too large or slow');
410
}
411
412
// HTTP response errors
413
if (error instanceof errors.ResponseStatusCodeError) {
414
switch (error.statusCode) {
415
case 400:
416
throw new Error('Bad request - check your request data');
417
case 401:
418
throw new Error('Authentication required');
419
case 403:
420
throw new Error('Access forbidden');
421
case 404:
422
throw new Error('Resource not found');
423
case 429:
424
throw new Error('Rate limit exceeded');
425
case 500:
426
throw new Error('Internal server error');
427
case 502:
428
case 503:
429
case 504:
430
throw new Error('Server temporarily unavailable');
431
default:
432
throw new Error(`HTTP ${error.statusCode}: ${error.message}`);
433
}
434
}
435
436
// Client state errors
437
if (error instanceof errors.ClientDestroyedError) {
438
throw new Error('HTTP client was destroyed');
439
}
440
441
if (error instanceof errors.RequestAbortedError) {
442
throw new Error('Request was cancelled');
443
}
444
445
// Protocol errors
446
if (error instanceof errors.HTTPParserError) {
447
throw new Error('Invalid HTTP response from server');
448
}
449
450
// Validation errors
451
if (error instanceof errors.InvalidArgumentError) {
452
throw new Error('Invalid request parameters');
453
}
454
455
// Unknown error
456
throw new Error(`Unexpected error: ${error.message}`);
457
}
458
}
459
```
460
461
### Retry with Error Classification
462
463
```javascript
464
import { request, errors } from 'undici';
465
466
async function requestWithRetry(url, options = {}, maxRetries = 3) {
467
let attempt = 0;
468
469
while (attempt <= maxRetries) {
470
try {
471
return await request(url, options);
472
} catch (error) {
473
attempt++;
474
475
// Don't retry client errors (4xx) or validation errors
476
if (
477
error instanceof errors.ResponseStatusCodeError &&
478
error.statusCode >= 400 && error.statusCode < 500
479
) {
480
throw error;
481
}
482
483
if (
484
error instanceof errors.InvalidArgumentError ||
485
error instanceof errors.NotSupportedError ||
486
error instanceof errors.ClientDestroyedError
487
) {
488
throw error;
489
}
490
491
// Retry on network errors, timeouts, and server errors
492
const shouldRetry =
493
error instanceof errors.ConnectTimeoutError ||
494
error instanceof errors.HeadersTimeoutError ||
495
error instanceof errors.BodyTimeoutError ||
496
error instanceof errors.SocketError ||
497
(error instanceof errors.ResponseStatusCodeError &&
498
error.statusCode >= 500);
499
500
if (!shouldRetry || attempt > maxRetries) {
501
throw error;
502
}
503
504
// Exponential backoff
505
const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
506
await new Promise(resolve => setTimeout(resolve, delay));
507
}
508
}
509
}
510
```
511
512
### Error Logging and Monitoring
513
514
```javascript
515
import { request, errors } from 'undici';
516
517
function logError(error, context = {}) {
518
const errorInfo = {
519
timestamp: new Date().toISOString(),
520
name: error.name,
521
code: error.code,
522
message: error.message,
523
...context
524
};
525
526
// Add specific error details
527
if (error instanceof errors.ResponseStatusCodeError) {
528
errorInfo.statusCode = error.statusCode;
529
errorInfo.headers = error.headers;
530
}
531
532
if (error instanceof errors.RequestRetryError) {
533
errorInfo.retryCount = error.data.count;
534
errorInfo.originalError = error.data.error.message;
535
}
536
537
if (error instanceof errors.SocketError && error.socket) {
538
errorInfo.socket = error.socket;
539
}
540
541
console.error('HTTP Request Error:', JSON.stringify(errorInfo, null, 2));
542
543
// Send to monitoring service
544
// monitoringService.logError(errorInfo);
545
}
546
547
async function monitoredRequest(url, options = {}) {
548
try {
549
return await request(url, options);
550
} catch (error) {
551
logError(error, { url, method: options.method || 'GET' });
552
throw error;
553
}
554
}
555
```