0
# Exception Handling
1
2
Comprehensive exception classes for timeout conditions, operation errors, connection failures, and Greengrass discovery issues. The AWS IoT Python SDK provides specific exceptions for different failure modes, enabling robust error handling and recovery strategies in IoT applications.
3
4
## Capabilities
5
6
### Base Exception Classes
7
8
Foundation exception classes that provide common error handling patterns.
9
10
```python { .api }
11
class operationError(Exception):
12
"""
13
Base class for operation-related errors in AWS IoT operations.
14
Raised when MQTT operations fail due to protocol or client issues.
15
"""
16
17
class operationTimeoutException(Exception):
18
"""
19
Base class for timeout-related errors in AWS IoT operations.
20
Raised when operations exceed configured timeout periods.
21
"""
22
23
class acceptTimeoutException(Exception):
24
"""
25
Raised when socket accept operation times out.
26
Used in low-level connection establishment scenarios.
27
"""
28
```
29
30
### Connection Exceptions
31
32
Exceptions related to MQTT connection establishment and management.
33
34
```python { .api }
35
class connectTimeoutException(operationTimeoutException):
36
"""Raised when MQTT connection attempt times out"""
37
38
class connectError(operationError):
39
"""Raised when MQTT connection fails due to protocol or authentication errors"""
40
41
class disconnectTimeoutException(operationTimeoutException):
42
"""Raised when MQTT disconnection attempt times out"""
43
44
class disconnectError(operationError):
45
"""Raised when MQTT disconnection fails"""
46
```
47
48
### Publish Operation Exceptions
49
50
Exceptions specific to MQTT publish operations and queue management.
51
52
```python { .api }
53
class publishTimeoutException(operationTimeoutException):
54
"""Raised when MQTT publish operation times out (QoS 1)"""
55
56
class publishError(operationError):
57
"""Raised when MQTT publish operation fails"""
58
59
class publishQueueFullException(operationError):
60
"""Raised when offline publish queue is full and configured to reject new messages"""
61
62
class publishQueueDisabledException(operationError):
63
"""Raised when attempting to queue publish messages but queueing is disabled"""
64
```
65
66
### Subscribe Operation Exceptions
67
68
Exceptions for MQTT subscription operations and acknowledgment handling.
69
70
```python { .api }
71
class subscribeTimeoutException(operationTimeoutException):
72
"""Raised when MQTT subscribe operation times out"""
73
74
class subscribeError(operationError):
75
"""Raised when MQTT subscribe operation fails"""
76
77
class subackError(operationError):
78
"""Raised when MQTT SUBACK indicates subscription failure"""
79
80
class subscribeQueueFullException(operationError):
81
"""Raised when offline subscribe queue is full"""
82
83
class subscribeQueueDisabledException(operationError):
84
"""Raised when attempting to queue subscribe operations but queueing is disabled"""
85
```
86
87
### Unsubscribe Operation Exceptions
88
89
Exceptions for MQTT unsubscribe operations.
90
91
```python { .api }
92
class unsubscribeTimeoutException(operationTimeoutException):
93
"""Raised when MQTT unsubscribe operation times out"""
94
95
class unsubscribeError(operationError):
96
"""Raised when MQTT unsubscribe operation fails"""
97
98
class unsubscribeQueueFullException(operationError):
99
"""Raised when offline unsubscribe queue is full"""
100
101
class unsubscribeQueueDisabledException(operationError):
102
"""Raised when attempting to queue unsubscribe operations but queueing is disabled"""
103
```
104
105
### WebSocket Exceptions
106
107
Exceptions specific to WebSocket SigV4 authentication and connection.
108
109
```python { .api }
110
class wssNoKeyInEnvironmentError(Exception):
111
"""Raised when WebSocket SigV4 credentials are missing from environment"""
112
113
class wssHandShakeError(Exception):
114
"""Raised when WebSocket handshake fails during connection establishment"""
115
```
116
117
### Greengrass Discovery Exceptions
118
119
Exceptions for Greengrass core discovery operations.
120
121
```python { .api }
122
class DiscoveryTimeoutException(Exception):
123
"""Raised when Greengrass discovery request times out"""
124
125
class DiscoveryUnauthorizedException(Exception):
126
"""Raised when Greengrass discovery authentication fails"""
127
128
class DiscoveryDataNotFoundException(Exception):
129
"""Raised when no Greengrass discovery data found for the specified thing"""
130
131
class DiscoveryInvalidRequestException(Exception):
132
"""Raised when Greengrass discovery request is malformed or invalid"""
133
134
class DiscoveryThrottlingException(Exception):
135
"""Raised when Greengrass discovery requests are being throttled"""
136
137
class DiscoveryFailure(Exception):
138
"""Raised for general Greengrass discovery service failures"""
139
```
140
141
### General Client Exceptions
142
143
General-purpose client error for miscellaneous failures.
144
145
```python { .api }
146
class ClientError(Exception):
147
"""General client error for SDK-wide failures and misconfigurations"""
148
```
149
150
## Usage Examples
151
152
### Basic Exception Handling
153
154
```python
155
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
156
from AWSIoTPythonSDK.exception.AWSIoTExceptions import (
157
connectTimeoutException,
158
connectError,
159
publishTimeoutException,
160
subscribeTimeoutException
161
)
162
163
# Create and configure client
164
client = AWSIoTPyMQTT.AWSIoTMQTTClient("errorHandlingClient")
165
client.configureEndpoint("endpoint.iot.region.amazonaws.com", 8883)
166
client.configureCredentials("rootCA.crt", "private.key", "certificate.crt")
167
168
# Configure timeouts
169
client.configureConnectDisconnectTimeout(10)
170
client.configureMQTTOperationTimeout(5)
171
172
try:
173
# Attempt connection with timeout handling
174
if not client.connect():
175
raise connectError("Failed to establish MQTT connection")
176
177
print("Connected successfully")
178
179
# Attempt publish with timeout handling
180
if not client.publish("test/topic", "Hello World", 1):
181
raise publishTimeoutException("Publish operation failed")
182
183
print("Message published successfully")
184
185
# Attempt subscribe with timeout handling
186
def messageCallback(client, userdata, message):
187
print(f"Received: {message.payload.decode()}")
188
189
if not client.subscribe("test/response", 1, messageCallback):
190
raise subscribeTimeoutException("Subscribe operation failed")
191
192
print("Subscribed successfully")
193
194
except connectTimeoutException:
195
print("Connection timed out - check network connectivity and endpoint")
196
197
except connectError:
198
print("Connection failed - check credentials and endpoint configuration")
199
200
except publishTimeoutException:
201
print("Publish timed out - message may not have been delivered")
202
203
except subscribeTimeoutException:
204
print("Subscribe timed out - subscription may not be active")
205
206
except Exception as e:
207
print(f"Unexpected error: {e}")
208
209
finally:
210
try:
211
client.disconnect()
212
except:
213
pass # Ignore disconnect errors in cleanup
214
```
215
216
### Queue Exception Handling
217
218
```python
219
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
220
from AWSIoTPythonSDK.exception.AWSIoTExceptions import (
221
publishQueueFullException,
222
publishQueueDisabledException
223
)
224
225
# Create client with limited queue
226
client = AWSIoTPyMQTT.AWSIoTMQTTClient("queueClient")
227
client.configureEndpoint("endpoint.iot.region.amazonaws.com", 8883)
228
client.configureCredentials("rootCA.crt", "private.key", "certificate.crt")
229
230
# Configure small queue for demonstration
231
client.configureOfflinePublishQueueing(5, AWSIoTPyMQTT.DROP_NEWEST)
232
233
try:
234
client.connect()
235
236
# Simulate offline condition by disconnecting
237
client.disconnect()
238
239
# Attempt to publish while offline
240
for i in range(10): # More messages than queue capacity
241
try:
242
message = f"Offline message {i}"
243
if not client.publish("offline/topic", message, 1):
244
print(f"Message {i} queued for offline delivery")
245
246
except publishQueueFullException:
247
print(f"Queue full - message {i} rejected")
248
# Implement retry logic or alternative handling
249
250
except publishQueueDisabledException:
251
print("Queueing is disabled - reconfigure client for offline operation")
252
break
253
254
except Exception as e:
255
print(f"Queue operation failed: {e}")
256
```
257
258
### Greengrass Discovery Exception Handling
259
260
```python
261
from AWSIoTPythonSDK.core.greengrass.discovery.providers import DiscoveryInfoProvider
262
from AWSIoTPythonSDK.exception.AWSIoTExceptions import (
263
DiscoveryTimeoutException,
264
DiscoveryUnauthorizedException,
265
DiscoveryDataNotFoundException,
266
DiscoveryThrottlingException,
267
DiscoveryFailure
268
)
269
import time
270
271
def robust_discovery(thing_name, max_retries=3):
272
"""Perform Greengrass discovery with comprehensive error handling"""
273
274
discoveryProvider = DiscoveryInfoProvider()
275
discoveryProvider.configureEndpoint("greengrass-ats.iot.region.amazonaws.com")
276
discoveryProvider.configureCredentials("rootCA.crt", "certificate.crt", "private.key")
277
discoveryProvider.configureTimeout(30)
278
279
for attempt in range(max_retries):
280
try:
281
print(f"Discovery attempt {attempt + 1}")
282
283
discoveryInfo = discoveryProvider.discover(thing_name)
284
print("Discovery successful")
285
return discoveryInfo
286
287
except DiscoveryTimeoutException:
288
print("Discovery timed out - check network connectivity")
289
if attempt < max_retries - 1:
290
print("Retrying with longer timeout...")
291
discoveryProvider.configureTimeout(60) # Increase timeout
292
time.sleep(5)
293
294
except DiscoveryUnauthorizedException:
295
print("Discovery authentication failed")
296
print("Check certificate validity and thing permissions")
297
return None # Don't retry auth failures
298
299
except DiscoveryDataNotFoundException:
300
print(f"No discovery data for thing: {thing_name}")
301
print("Ensure thing is associated with a Greengrass group")
302
return None # Don't retry data not found
303
304
except DiscoveryThrottlingException:
305
print("Discovery requests are being throttled")
306
if attempt < max_retries - 1:
307
backoff_time = 2 ** attempt # Exponential backoff
308
print(f"Backing off for {backoff_time} seconds...")
309
time.sleep(backoff_time)
310
311
except DiscoveryFailure as e:
312
print(f"Discovery service failure: {e}")
313
if attempt < max_retries - 1:
314
print("Retrying discovery request...")
315
time.sleep(2)
316
317
except Exception as e:
318
print(f"Unexpected discovery error: {e}")
319
if attempt < max_retries - 1:
320
time.sleep(2)
321
322
print(f"Discovery failed after {max_retries} attempts")
323
return None
324
325
# Usage
326
discovery_result = robust_discovery("myIoTDevice")
327
if discovery_result:
328
cores = discovery_result.getAllCores()
329
print(f"Found {len(cores)} Greengrass cores")
330
else:
331
print("Discovery failed - falling back to direct AWS IoT connection")
332
```
333
334
### Comprehensive Error Recovery
335
336
```python
337
import AWSIoTPythonSDK.MQTTLib as AWSIoTPyMQTT
338
from AWSIoTPythonSDK.exception.AWSIoTExceptions import *
339
import time
340
import logging
341
342
# Configure logging
343
logging.basicConfig(level=logging.INFO)
344
logger = logging.getLogger(__name__)
345
346
class RobustIoTClient:
347
"""IoT client with comprehensive error handling and recovery"""
348
349
def __init__(self, client_id, endpoint, port=8883):
350
self.client_id = client_id
351
self.endpoint = endpoint
352
self.port = port
353
self.client = None
354
self.connected = False
355
self.max_retries = 3
356
self.retry_delay = 5
357
358
def configure_credentials(self, ca_path, key_path, cert_path):
359
"""Configure client credentials"""
360
self.ca_path = ca_path
361
self.key_path = key_path
362
self.cert_path = cert_path
363
364
def create_client(self):
365
"""Create and configure MQTT client"""
366
self.client = AWSIoTPyMQTT.AWSIoTMQTTClient(self.client_id)
367
self.client.configureEndpoint(self.endpoint, self.port)
368
self.client.configureCredentials(self.ca_path, self.key_path, self.cert_path)
369
370
# Configure timeouts and reconnection
371
self.client.configureConnectDisconnectTimeout(10)
372
self.client.configureMQTTOperationTimeout(5)
373
self.client.configureAutoReconnectBackoffTime(1, 32, 20)
374
self.client.configureOfflinePublishQueueing(-1) # Infinite queue
375
376
def connect_with_retry(self):
377
"""Connect with automatic retry and error handling"""
378
for attempt in range(self.max_retries):
379
try:
380
logger.info(f"Connection attempt {attempt + 1}")
381
382
if self.client.connect():
383
self.connected = True
384
logger.info("Connected successfully")
385
return True
386
else:
387
raise connectError("Connection returned False")
388
389
except connectTimeoutException:
390
logger.warning(f"Connection timeout on attempt {attempt + 1}")
391
392
except connectError as e:
393
logger.error(f"Connection error: {e}")
394
395
except Exception as e:
396
logger.error(f"Unexpected connection error: {e}")
397
398
if attempt < self.max_retries - 1:
399
logger.info(f"Retrying in {self.retry_delay} seconds...")
400
time.sleep(self.retry_delay)
401
402
logger.error("Failed to connect after all retries")
403
return False
404
405
def publish_with_retry(self, topic, payload, qos=0):
406
"""Publish with error handling and retry logic"""
407
if not self.connected:
408
logger.warning("Not connected - attempting reconnection")
409
if not self.connect_with_retry():
410
return False
411
412
for attempt in range(self.max_retries):
413
try:
414
if self.client.publish(topic, payload, qos):
415
logger.info(f"Published to {topic}")
416
return True
417
else:
418
raise publishError("Publish returned False")
419
420
except publishTimeoutException:
421
logger.warning(f"Publish timeout on attempt {attempt + 1}")
422
423
except publishQueueFullException:
424
logger.warning("Publish queue full - clearing some messages")
425
# Could implement queue management logic here
426
427
except publishError as e:
428
logger.error(f"Publish error: {e}")
429
430
except Exception as e:
431
logger.error(f"Unexpected publish error: {e}")
432
433
if attempt < self.max_retries - 1:
434
time.sleep(1)
435
436
logger.error(f"Failed to publish to {topic} after all retries")
437
return False
438
439
def subscribe_with_retry(self, topic, qos, callback):
440
"""Subscribe with error handling"""
441
if not self.connected:
442
if not self.connect_with_retry():
443
return False
444
445
try:
446
if self.client.subscribe(topic, qos, callback):
447
logger.info(f"Subscribed to {topic}")
448
return True
449
else:
450
raise subscribeError("Subscribe returned False")
451
452
except subscribeTimeoutException:
453
logger.error("Subscribe operation timed out")
454
455
except subackError:
456
logger.error("Subscribe was rejected by broker")
457
458
except subscribeError as e:
459
logger.error(f"Subscribe error: {e}")
460
461
except Exception as e:
462
logger.error(f"Unexpected subscribe error: {e}")
463
464
return False
465
466
def disconnect_safely(self):
467
"""Disconnect with error handling"""
468
if not self.connected:
469
return
470
471
try:
472
self.client.disconnect()
473
self.connected = False
474
logger.info("Disconnected successfully")
475
476
except disconnectTimeoutException:
477
logger.warning("Disconnect timed out")
478
479
except disconnectError as e:
480
logger.error(f"Disconnect error: {e}")
481
482
except Exception as e:
483
logger.error(f"Unexpected disconnect error: {e}")
484
485
# Usage example
486
client = RobustIoTClient("robustClient", "endpoint.iot.region.amazonaws.com")
487
client.configure_credentials("rootCA.crt", "private.key", "certificate.crt")
488
client.create_client()
489
490
if client.connect_with_retry():
491
# Publish with error handling
492
client.publish_with_retry("test/topic", "Hello World", 1)
493
494
# Subscribe with error handling
495
def message_callback(client, userdata, message):
496
print(f"Received: {message.payload.decode()}")
497
498
client.subscribe_with_retry("test/response", 1, message_callback)
499
500
# Keep running
501
try:
502
time.sleep(30)
503
finally:
504
client.disconnect_safely()
505
```
506
507
## Types
508
509
```python { .api }
510
# Exception hierarchy structure
511
Exception
512
├── acceptTimeoutException
513
├── operationError
514
│ ├── connectError
515
│ ├── disconnectError
516
│ ├── publishError
517
│ ├── publishQueueFullException
518
│ ├── publishQueueDisabledException
519
│ ├── subscribeError
520
│ ├── subackError
521
│ ├── subscribeQueueFullException
522
│ ├── subscribeQueueDisabledException
523
│ ├── unsubscribeError
524
│ ├── unsubscribeQueueFullException
525
│ └── unsubscribeQueueDisabledException
526
├── operationTimeoutException
527
│ ├── connectTimeoutException
528
│ ├── disconnectTimeoutException
529
│ ├── publishTimeoutException
530
│ ├── subscribeTimeoutException
531
│ └── unsubscribeTimeoutException
532
├── wssNoKeyInEnvironmentError
533
├── wssHandShakeError
534
├── DiscoveryTimeoutException
535
├── DiscoveryUnauthorizedException
536
├── DiscoveryDataNotFoundException
537
├── DiscoveryInvalidRequestException
538
├── DiscoveryThrottlingException
539
├── DiscoveryFailure
540
└── ClientError
541
542
# Exception handling best practices
543
error_handling_patterns = {
544
"timeout_exceptions": "Retry with backoff, check network connectivity",
545
"auth_exceptions": "Don't retry, check credentials and permissions",
546
"queue_exceptions": "Implement queue management or fallback strategies",
547
"discovery_exceptions": "Use exponential backoff, fallback to direct connection",
548
"general_errors": "Log error details, implement graceful degradation"
549
}
550
```