0
# Exception Handling
1
2
Comprehensive exception hierarchy for handling different types of HTTP errors, timeouts, connection issues, and protocol violations. HTTP3 provides specific exception types that enable precise error handling and appropriate recovery strategies.
3
4
## Capabilities
5
6
### Timeout Exceptions
7
8
Exceptions related to various timeout scenarios during HTTP operations.
9
10
```python { .api }
11
class Timeout(Exception):
12
"""
13
Base class for all timeout exceptions.
14
15
All timeout-related exceptions inherit from this class, allowing
16
you to catch any timeout condition with a single except block.
17
"""
18
19
class ConnectTimeout(Timeout):
20
"""
21
Timeout while establishing a connection.
22
23
Raised when the client cannot establish a TCP connection to the
24
server within the specified connect_timeout period.
25
"""
26
27
class ReadTimeout(Timeout):
28
"""
29
Timeout while reading response data.
30
31
Raised when the server doesn't send response data within the
32
specified read_timeout period after connection is established.
33
"""
34
35
class WriteTimeout(Timeout):
36
"""
37
Timeout while writing request data.
38
39
Raised when the client cannot send request data to the server
40
within the specified write_timeout period.
41
"""
42
43
class PoolTimeout(Timeout):
44
"""
45
Timeout while waiting to acquire a connection from the pool.
46
47
Raised when no connection becomes available in the connection
48
pool within the specified pool_timeout period.
49
"""
50
```
51
52
**Usage Example:**
53
54
```python
55
import http3
56
57
try:
58
response = http3.get('https://slow-server.example.com', timeout=5.0)
59
except http3.ConnectTimeout:
60
print("Could not connect to server")
61
except http3.ReadTimeout:
62
print("Server didn't respond in time")
63
except http3.WriteTimeout:
64
print("Could not send request data")
65
except http3.PoolTimeout:
66
print("No connection available in pool")
67
except http3.Timeout:
68
print("Some kind of timeout occurred")
69
```
70
71
### HTTP Protocol Exceptions
72
73
Exceptions related to HTTP protocol violations and general HTTP errors.
74
75
```python { .api }
76
class ProtocolError(Exception):
77
"""
78
Malformed HTTP protocol data.
79
80
Raised when the server sends invalid HTTP data that violates
81
the HTTP specification, such as malformed headers or invalid
82
response structure.
83
"""
84
85
class DecodingError(Exception):
86
"""
87
Content decoding failure.
88
89
Raised when response content cannot be decoded properly,
90
such as invalid UTF-8 encoding or corrupted compressed data.
91
"""
92
93
class InvalidURL(Exception):
94
"""
95
Invalid URL format.
96
97
Raised when a provided URL is malformed, missing required
98
components (scheme, host), or contains invalid characters.
99
"""
100
```
101
102
**Usage Example:**
103
104
```python
105
import http3
106
107
try:
108
response = http3.get('invalid://url')
109
except http3.InvalidURL:
110
print("URL format is invalid")
111
112
try:
113
response = http3.get('https://api.example.com/data')
114
data = response.json()
115
except http3.ProtocolError:
116
print("Server sent malformed HTTP data")
117
except http3.DecodingError:
118
print("Could not decode response content")
119
```
120
121
### Redirect Exceptions
122
123
Exceptions related to HTTP redirect handling and redirect loops.
124
125
```python { .api }
126
class TooManyRedirects(Exception):
127
"""
128
Too many redirects occurred.
129
130
Raised when the number of redirects exceeds the maximum
131
allowed limit (typically 20 by default).
132
"""
133
134
class RedirectBodyUnavailable(Exception):
135
"""
136
Redirect attempted but request body was streaming and is no longer available.
137
138
Raised when a POST/PUT request with streaming body encounters
139
a redirect, but the body cannot be replayed for the redirect.
140
"""
141
142
class RedirectLoop(Exception):
143
"""
144
Infinite redirect loop detected.
145
146
Raised when the client detects that redirects are forming
147
a loop, visiting the same URLs repeatedly.
148
"""
149
```
150
151
**Usage Example:**
152
153
```python
154
import http3
155
156
try:
157
response = http3.get('https://example.com/redirect-loop')
158
except http3.TooManyRedirects:
159
print("Too many redirects - possible redirect loop")
160
except http3.RedirectLoop:
161
print("Infinite redirect loop detected")
162
163
try:
164
with open('large-file.bin', 'rb') as f:
165
response = http3.post('https://example.com/upload', data=f)
166
except http3.RedirectBodyUnavailable:
167
print("Cannot redirect streaming request body")
168
```
169
170
### Stream Exceptions
171
172
Exceptions related to response streaming and content access patterns.
173
174
```python { .api }
175
class StreamConsumed(Exception):
176
"""
177
Attempted to read or stream response content that has already been consumed.
178
179
Raised when trying to access response content after it has
180
already been read through streaming or direct access.
181
"""
182
183
class ResponseNotRead(Exception):
184
"""
185
Attempted to access response content without reading it first.
186
187
Raised when trying to access response content properties
188
after a streaming response that hasn't been fully read.
189
"""
190
191
class ResponseClosed(Exception):
192
"""
193
Attempted to read or stream response content from a closed response.
194
195
Raised when trying to access content from a response that
196
has been explicitly closed or whose connection was terminated.
197
"""
198
```
199
200
**Usage Example:**
201
202
```python
203
import http3
204
205
try:
206
response = http3.get('https://api.example.com/data', stream=True)
207
208
# Consume the stream
209
for chunk in response.iter_content():
210
process_chunk(chunk)
211
212
# This will raise StreamConsumed
213
text = response.text
214
215
except http3.StreamConsumed:
216
print("Response content already consumed")
217
except http3.ResponseNotRead:
218
print("Response not fully read")
219
except http3.ResponseClosed:
220
print("Response connection closed")
221
```
222
223
### Connection Exceptions
224
225
Exceptions related to connection management and network issues.
226
227
```python { .api }
228
class NotConnected(Exception):
229
"""
230
Connection was lost at the point of starting a request.
231
232
Raised when a connection is lost before any request data
233
has been successfully sent.
234
"""
235
236
class CookieConflict(Exception):
237
"""
238
Attempted to lookup a cookie by name, but multiple cookies existed.
239
240
Raised when trying to access a cookie by name when multiple
241
cookies with the same name exist for different domains/paths.
242
"""
243
```
244
245
## Error Handling Strategies
246
247
### Comprehensive Error Handling
248
249
```python
250
import http3
251
import time
252
253
def robust_request(url, max_retries=3, backoff_factor=1.0):
254
"""Make a request with comprehensive error handling and retries."""
255
256
for attempt in range(max_retries):
257
try:
258
response = http3.get(url, timeout=30.0)
259
response.raise_for_status() # Raise for HTTP error status codes
260
return response
261
262
except http3.ConnectTimeout:
263
print(f"Connection timeout (attempt {attempt + 1})")
264
if attempt < max_retries - 1:
265
time.sleep(backoff_factor * (2 ** attempt))
266
continue
267
raise
268
269
except http3.ReadTimeout:
270
print(f"Read timeout (attempt {attempt + 1})")
271
if attempt < max_retries - 1:
272
time.sleep(backoff_factor * (2 ** attempt))
273
continue
274
raise
275
276
except http3.ProtocolError as e:
277
print(f"Protocol error: {e}")
278
# Don't retry protocol errors
279
raise
280
281
except http3.TooManyRedirects:
282
print("Too many redirects")
283
# Don't retry redirect errors
284
raise
285
286
except http3.InvalidURL as e:
287
print(f"Invalid URL: {e}")
288
# Don't retry URL errors
289
raise
290
291
except Exception as e:
292
print(f"Unexpected error: {e}")
293
if attempt < max_retries - 1:
294
time.sleep(backoff_factor * (2 ** attempt))
295
continue
296
raise
297
298
# Usage
299
try:
300
response = robust_request('https://api.example.com/data')
301
data = response.json()
302
except http3.Timeout:
303
print("Request timed out after retries")
304
except http3.ProtocolError:
305
print("Server sent invalid HTTP data")
306
except Exception as e:
307
print(f"Request failed: {e}")
308
```
309
310
### Async Error Handling
311
312
```python
313
import http3
314
import asyncio
315
316
async def async_request_with_handling(url):
317
"""Async request with proper error handling."""
318
319
try:
320
async with http3.AsyncClient(timeout=30.0) as client:
321
response = await client.get(url)
322
323
# Check for HTTP errors
324
if response.is_error:
325
print(f"HTTP Error: {response.status_code}")
326
return None
327
328
return await response.json()
329
330
except http3.ConnectTimeout:
331
print("Could not connect to server")
332
except http3.ReadTimeout:
333
print("Server response timeout")
334
except http3.ProtocolError as e:
335
print(f"Protocol error: {e}")
336
except http3.DecodingError as e:
337
print(f"Content decoding error: {e}")
338
except Exception as e:
339
print(f"Unexpected error: {e}")
340
341
return None
342
343
# Usage
344
async def main():
345
data = await async_request_with_handling('https://api.example.com/data')
346
if data:
347
print(f"Received data: {data}")
348
349
asyncio.run(main())
350
```
351
352
### Context-Specific Error Handling
353
354
```python
355
import http3
356
357
def handle_api_request(url, api_key):
358
"""Handle API requests with context-specific error handling."""
359
360
try:
361
response = http3.get(
362
url,
363
headers={'Authorization': f'Bearer {api_key}'},
364
timeout=10.0
365
)
366
367
# Handle HTTP status codes
368
if response.status_code == 401:
369
raise AuthenticationError("Invalid API key")
370
elif response.status_code == 429:
371
raise RateLimitError("Rate limit exceeded")
372
elif response.status_code >= 500:
373
raise ServerError(f"Server error: {response.status_code}")
374
375
response.raise_for_status()
376
return response.json()
377
378
except http3.ConnectTimeout:
379
raise NetworkError("Cannot connect to API server")
380
except http3.ReadTimeout:
381
raise NetworkError("API server response timeout")
382
except http3.InvalidURL:
383
raise ConfigurationError("Invalid API URL")
384
except http3.DecodingError:
385
raise DataError("Invalid response format")
386
387
# Custom exception hierarchy
388
class APIError(Exception):
389
"""Base API error."""
390
391
class NetworkError(APIError):
392
"""Network-related error."""
393
394
class AuthenticationError(APIError):
395
"""Authentication error."""
396
397
class RateLimitError(APIError):
398
"""Rate limit error."""
399
400
class ServerError(APIError):
401
"""Server error."""
402
403
class ConfigurationError(APIError):
404
"""Configuration error."""
405
406
class DataError(APIError):
407
"""Data processing error."""
408
```
409
410
### Response Streaming Error Handling
411
412
```python
413
import http3
414
415
def download_file_with_error_handling(url, filename):
416
"""Download a file with proper streaming error handling."""
417
418
try:
419
response = http3.get(url, stream=True)
420
response.raise_for_status()
421
422
with open(filename, 'wb') as f:
423
try:
424
for chunk in response.iter_content(chunk_size=8192):
425
f.write(chunk)
426
427
except http3.ReadTimeout:
428
print("Download interrupted - read timeout")
429
response.close()
430
# Remove partial file
431
import os
432
if os.path.exists(filename):
433
os.remove(filename)
434
raise
435
436
except http3.StreamConsumed:
437
print("Stream already consumed")
438
raise
439
440
except http3.ResponseClosed:
441
print("Connection closed during download")
442
raise
443
444
print(f"Downloaded {filename} successfully")
445
446
except http3.ConnectTimeout:
447
print("Could not connect to download server")
448
except http3.ProtocolError:
449
print("Invalid response from server")
450
except Exception as e:
451
print(f"Download failed: {e}")
452
# Clean up partial file
453
import os
454
if os.path.exists(filename):
455
os.remove(filename)
456
raise
457
458
# Usage
459
try:
460
download_file_with_error_handling(
461
'https://example.com/large-file.zip',
462
'downloaded-file.zip'
463
)
464
except Exception:
465
print("Download failed")
466
```
467
468
## Exception Hierarchy Summary
469
470
```
471
Exception
472
├── Timeout
473
│ ├── ConnectTimeout
474
│ ├── ReadTimeout
475
│ ├── WriteTimeout
476
│ └── PoolTimeout
477
├── ProtocolError
478
├── DecodingError
479
├── InvalidURL
480
├── TooManyRedirects
481
├── RedirectBodyUnavailable
482
├── RedirectLoop
483
├── StreamConsumed
484
├── ResponseNotRead
485
├── ResponseClosed
486
├── NotConnected
487
└── CookieConflict
488
```
489
490
This hierarchy allows for both specific and general exception handling patterns depending on your application's needs.