0
# Exception Handling and Error Management
1
2
Bleak provides a comprehensive exception hierarchy for handling BLE operation errors, device connectivity issues, and platform-specific error conditions. The exception system includes detailed error information and platform-specific error code mappings.
3
4
## Capabilities
5
6
### Base Exception Class
7
8
Foundation exception class for all Bleak-related errors.
9
10
```python { .api }
11
class BleakError(Exception):
12
"""
13
Base exception for all Bleak operations.
14
15
All Bleak-specific exceptions inherit from this class, allowing
16
for unified exception handling.
17
"""
18
```
19
20
### Characteristic Not Found Error
21
22
Specialized exception for missing or inaccessible characteristics.
23
24
```python { .api }
25
class BleakCharacteristicNotFoundError(BleakError):
26
"""
27
Exception raised when a characteristic cannot be found.
28
29
Raised when attempting to access a characteristic that doesn't exist
30
or is not accessible on the connected device.
31
"""
32
33
char_specifier: Union[int, str, uuid.UUID]
34
"""The characteristic specifier that was not found."""
35
36
def __init__(self, char_specifier: Union[int, str, uuid.UUID]) -> None:
37
"""
38
Initialize characteristic not found error.
39
40
Args:
41
char_specifier: Handle or UUID of the characteristic that was not found
42
"""
43
```
44
45
### Device Not Found Error
46
47
Exception for devices that cannot be located or accessed by the OS Bluetooth stack.
48
49
```python { .api }
50
class BleakDeviceNotFoundError(BleakError):
51
"""
52
Exception raised when a device cannot be found for connection operations.
53
54
This occurs when the OS Bluetooth stack has never seen the device,
55
or when the device was removed and forgotten from the OS.
56
"""
57
58
identifier: str
59
"""The device identifier (address or UUID) that was not found."""
60
61
def __init__(self, identifier: str, *args: object) -> None:
62
"""
63
Initialize device not found error.
64
65
Args:
66
identifier: Device identifier (Bluetooth address or UUID) that was not found
67
*args: Additional exception arguments
68
"""
69
```
70
71
### D-Bus Error (Linux/BlueZ Specific)
72
73
Specialized exception for BlueZ backend D-Bus communication errors.
74
75
```python { .api }
76
class BleakDBusError(BleakError):
77
"""
78
Specialized exception for D-Bus errors in the BlueZ backend.
79
80
Provides detailed information about D-Bus communication failures
81
and includes mappings for common protocol error codes.
82
"""
83
84
def __init__(self, dbus_error: str, error_body: list[Any]):
85
"""
86
Initialize D-Bus error.
87
88
Args:
89
dbus_error: D-Bus error name (e.g., 'org.freedesktop.DBus.Error.UnknownObject')
90
error_body: List containing error description or details
91
"""
92
93
@property
94
def dbus_error(self) -> str:
95
"""Gets the D-Bus error name."""
96
97
@property
98
def dbus_error_details(self) -> Optional[str]:
99
"""
100
Gets optional D-Bus error details with enhanced descriptions.
101
102
Automatically enhances ATT error codes with human-readable descriptions.
103
"""
104
105
def __str__(self) -> str:
106
"""Format error with name and details."""
107
```
108
109
### Error Code Constants
110
111
Comprehensive error code mappings for Bluetooth controller and GATT protocol errors.
112
113
```python { .api }
114
# Bluetooth controller error codes
115
CONTROLLER_ERROR_CODES: dict[int, str] = {
116
0x00: "Success",
117
0x01: "Unknown HCI Command",
118
0x02: "Unknown Connection Identifier",
119
0x03: "Hardware Failure",
120
0x04: "Page Timeout",
121
0x05: "Authentication Failure",
122
0x06: "PIN or Key Missing",
123
0x07: "Memory Capacity Exceeded",
124
0x08: "Connection Timeout",
125
0x09: "Connection Limit Exceeded",
126
0x0A: "Synchronous Connection Limit To A Device Exceeded",
127
0x0B: "Connection Already Exists",
128
0x0C: "Command Disallowed",
129
0x0D: "Connection Rejected due to Limited Resources",
130
0x0E: "Connection Rejected Due To Security Reasons",
131
0x0F: "Connection Rejected due to Unacceptable BD_ADDR",
132
0x10: "Connection Accept Timeout Exceeded",
133
0x11: "Unsupported Feature or Parameter Value",
134
0x12: "Invalid HCI Command Parameters",
135
0x13: "Remote User Terminated Connection",
136
0x14: "Remote Device Terminated Connection due to Low Resources",
137
0x15: "Remote Device Terminated Connection due to Power Off",
138
0x16: "Connection Terminated By Local Host",
139
0x17: "Repeated Attempts",
140
0x18: "Pairing Not Allowed",
141
0x19: "Unknown LMP PDU",
142
0x1A: "Unsupported Remote Feature / Unsupported LMP Feature",
143
0x1B: "SCO Offset Rejected",
144
0x1C: "SCO Interval Rejected",
145
0x1D: "SCO Air Mode Rejected",
146
0x1E: "Invalid LMP Parameters / Invalid LL Parameters",
147
0x1F: "Unspecified Error",
148
0x20: "Unsupported LMP Parameter Value / Unsupported LL Parameter Value",
149
0x21: "Role Change Not Allowed",
150
0x22: "LMP Response Timeout / LL Response Timeout",
151
0x23: "LMP Error Transaction Collision / LL Procedure Collision",
152
0x24: "LMP PDU Not Allowed",
153
0x25: "Encryption Mode Not Acceptable",
154
0x26: "Link Key cannot be Changed",
155
0x27: "Requested QoS Not Supported",
156
0x28: "Instant Passed",
157
0x29: "Pairing With Unit Key Not Supported",
158
0x2A: "Different Transaction Collision",
159
0x2B: "Reserved for future use",
160
0x2C: "QoS Unacceptable Parameter",
161
0x2D: "QoS Rejected",
162
0x2E: "Channel Classification Not Supported",
163
0x2F: "Insufficient Security",
164
0x30: "Parameter Out Of Mandatory Range",
165
0x31: "Reserved for future use",
166
0x32: "Role Switch Pending",
167
0x33: "Reserved for future use",
168
0x34: "Reserved Slot Violation",
169
0x35: "Role Switch Failed",
170
0x36: "Extended Inquiry Response Too Large",
171
0x37: "Secure Simple Pairing Not Supported By Host",
172
0x38: "Host Busy - Pairing",
173
0x39: "Connection Rejected due to No Suitable Channel Found",
174
0x3A: "Controller Busy",
175
0x3B: "Unacceptable Connection Parameters",
176
0x3C: "Advertising Timeout",
177
0x3D: "Connection Terminated due to MIC Failure",
178
0x3E: "Connection Failed to be Established / Synchronization Timeout",
179
0x3F: "MAC Connection Failed",
180
0x40: "Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock",
181
0x41: "Type0 Submap Not Defined",
182
0x42: "Unknown Advertising Identifier",
183
0x43: "Limit Reached",
184
0x44: "Operation Cancelled by Host",
185
0x45: "Packet Too Long",
186
}
187
188
# GATT protocol error codes
189
PROTOCOL_ERROR_CODES: dict[int, str] = {
190
0x01: "Invalid Handle",
191
0x02: "Read Not Permitted",
192
0x03: "Write Not Permitted",
193
0x04: "Invalid PDU",
194
0x05: "Insufficient Authentication",
195
0x06: "Request Not Supported",
196
0x07: "Invalid Offset",
197
0x08: "Insufficient Authorization",
198
0x09: "Prepare Queue Full",
199
0x0A: "Attribute Not Found",
200
0x0B: "Attribute Not Long",
201
0x0C: "Insufficient Encryption Key Size",
202
0x0D: "Invalid Attribute Value Length",
203
0x0E: "Unlikely Error",
204
0x0F: "Insufficient Encryption",
205
0x10: "Unsupported Group Type",
206
0x11: "Insufficient Resource",
207
0x12: "Database Out Of Sync",
208
0x13: "Value Not Allowed",
209
0xFC: "Write Request Rejected",
210
0xFD: "Client Characteristic Configuration Descriptor Improperly Configured",
211
0xFE: "Procedure Already in Progress",
212
0xFF: "Out of Range",
213
}
214
```
215
216
## Usage Examples
217
218
### Basic Exception Handling
219
220
```python
221
import asyncio
222
from bleak import BleakClient, BleakError, BleakCharacteristicNotFoundError
223
224
async def safe_characteristic_read():
225
address = "00:11:22:33:44:55" # Replace with actual device address
226
char_uuid = "00002a19-0000-1000-8000-00805f9b34fb" # Battery Level
227
228
try:
229
async with BleakClient(address) as client:
230
# Attempt to read characteristic
231
data = await client.read_gatt_char(char_uuid)
232
battery_level = int.from_bytes(data, byteorder='little')
233
print(f"Battery level: {battery_level}%")
234
235
except BleakCharacteristicNotFoundError as e:
236
print(f"Characteristic not found: {e.char_specifier}")
237
print("Device may not support battery level reporting")
238
239
except BleakError as e:
240
print(f"BLE operation failed: {e}")
241
242
except Exception as e:
243
print(f"Unexpected error: {e}")
244
245
asyncio.run(safe_characteristic_read())
246
```
247
248
### Connection Error Handling
249
250
```python
251
import asyncio
252
from bleak import BleakClient, BleakDeviceNotFoundError, BleakError
253
254
async def safe_connection():
255
address = "00:11:22:33:44:55" # Replace with actual device address
256
257
try:
258
client = BleakClient(address, timeout=10.0)
259
await client.connect()
260
261
print(f"Connected to {client.name}")
262
print(f"Address: {client.address}")
263
print(f"Connected: {client.is_connected}")
264
265
# Perform operations...
266
267
await client.disconnect()
268
269
except BleakDeviceNotFoundError as e:
270
print(f"Device not found: {e.identifier}")
271
print("Make sure the device is powered on and in range")
272
273
except asyncio.TimeoutError:
274
print("Connection timed out")
275
print("Device may be out of range or not advertising")
276
277
except BleakError as e:
278
print(f"Connection failed: {e}")
279
280
except Exception as e:
281
print(f"Unexpected error during connection: {e}")
282
283
asyncio.run(safe_connection())
284
```
285
286
### Platform-Specific Error Handling
287
288
```python
289
import asyncio
290
import platform
291
from bleak import BleakClient, BleakDBusError, BleakError
292
293
async def platform_specific_handling():
294
address = "00:11:22:33:44:55" # Replace with actual device address
295
296
try:
297
async with BleakClient(address) as client:
298
# Attempt some operation
299
services = client.services
300
print(f"Discovered {len(services.services)} services")
301
302
except BleakDBusError as e:
303
# Linux/BlueZ specific error handling
304
print(f"D-Bus error: {e.dbus_error}")
305
if e.dbus_error_details:
306
print(f"Details: {e.dbus_error_details}")
307
308
# Handle specific D-Bus errors
309
if "org.freedesktop.DBus.Error.UnknownObject" in e.dbus_error:
310
print("Device object not found in BlueZ")
311
elif "org.bluez.Error.NotReady" in e.dbus_error:
312
print("Bluetooth adapter not ready")
313
314
except BleakError as e:
315
print(f"General BLE error: {e}")
316
317
# Platform-specific advice
318
if platform.system() == "Darwin": # macOS
319
print("Note: On macOS, device addresses are UUIDs, not MAC addresses")
320
elif platform.system() == "Windows":
321
print("Note: On Windows, ensure device is paired if required")
322
elif platform.system() == "Linux":
323
print("Note: On Linux, ensure BlueZ is running and user has permissions")
324
325
asyncio.run(platform_specific_handling())
326
```
327
328
### Notification Error Handling
329
330
```python
331
import asyncio
332
from bleak import BleakClient, BleakError, BleakCharacteristicNotFoundError
333
334
def notification_handler(characteristic, data):
335
print(f"Notification: {data.hex()}")
336
337
async def safe_notifications():
338
address = "00:11:22:33:44:55" # Replace with actual device address
339
notify_char = "12345678-1234-5678-9012-123456789abc" # Replace with actual UUID
340
341
try:
342
async with BleakClient(address) as client:
343
# Check if characteristic exists and supports notifications
344
char = client.services.get_characteristic(notify_char)
345
if not char:
346
raise BleakCharacteristicNotFoundError(notify_char)
347
348
if "notify" not in char.properties:
349
print(f"Characteristic {notify_char} does not support notifications")
350
return
351
352
# Start notifications
353
await client.start_notify(notify_char, notification_handler)
354
print("Notifications started successfully")
355
356
# Keep connection alive
357
await asyncio.sleep(30)
358
359
# Stop notifications (automatic on disconnect)
360
await client.stop_notify(notify_char)
361
print("Notifications stopped")
362
363
except BleakCharacteristicNotFoundError as e:
364
print(f"Notification characteristic not found: {e.char_specifier}")
365
366
except BleakError as e:
367
print(f"Notification setup failed: {e}")
368
369
# Check for common notification issues
370
error_str = str(e).lower()
371
if "not connected" in error_str:
372
print("Ensure device is connected before starting notifications")
373
elif "cccd" in error_str or "descriptor" in error_str:
374
print("Device may not support notifications on this characteristic")
375
376
asyncio.run(safe_notifications())
377
```
378
379
### Write Operation Error Handling
380
381
```python
382
import asyncio
383
from bleak import BleakClient, BleakError, BleakCharacteristicNotFoundError
384
385
async def safe_write_operations():
386
address = "00:11:22:33:44:55" # Replace with actual device address
387
write_char = "12345678-1234-5678-9012-123456789abc" # Replace with actual UUID
388
389
try:
390
async with BleakClient(address) as client:
391
# Check if characteristic supports writing
392
char = client.services.get_characteristic(write_char)
393
if not char:
394
raise BleakCharacteristicNotFoundError(write_char)
395
396
# Check write capabilities
397
can_write = "write" in char.properties
398
can_write_no_response = "write-without-response" in char.properties
399
400
if not (can_write or can_write_no_response):
401
print(f"Characteristic {write_char} does not support writing")
402
return
403
404
data = b"Hello, BLE device!"
405
406
# Attempt write with response if supported
407
if can_write:
408
try:
409
await client.write_gatt_char(write_char, data, response=True)
410
print("Write with response successful")
411
except BleakError as e:
412
print(f"Write with response failed: {e}")
413
414
# Try write without response as fallback
415
if can_write_no_response:
416
await client.write_gatt_char(write_char, data, response=False)
417
print("Fallback write without response successful")
418
else:
419
# Only write without response available
420
await client.write_gatt_char(write_char, data, response=False)
421
print("Write without response successful")
422
423
except BleakCharacteristicNotFoundError as e:
424
print(f"Write characteristic not found: {e.char_specifier}")
425
426
except BleakError as e:
427
print(f"Write operation failed: {e}")
428
429
# Handle common write errors
430
error_str = str(e).lower()
431
if "mtu" in error_str or "size" in error_str:
432
print("Data may be too large for device MTU")
433
print(f"Try reducing data size (current: {len(data)} bytes)")
434
elif "authentication" in error_str or "permission" in error_str:
435
print("Write may require device pairing or authentication")
436
437
asyncio.run(safe_write_operations())
438
```
439
440
### Service Discovery Error Handling
441
442
```python
443
import asyncio
444
from bleak import BleakClient, BleakError
445
446
async def safe_service_discovery():
447
address = "00:11:22:33:44:55" # Replace with actual device address
448
449
try:
450
async with BleakClient(address) as client:
451
print(f"Connected to {client.name}")
452
453
# Access services (triggers service discovery if not done)
454
try:
455
services = client.services
456
print(f"Discovered {len(services.services)} services")
457
458
# Verify service discovery completed successfully
459
if not services.services:
460
print("Warning: No services discovered - device may not be fully connected")
461
462
# List discovered services
463
for service in services:
464
print(f"Service: {service.uuid} - {service.description}")
465
466
except BleakError as e:
467
print(f"Service discovery failed: {e}")
468
469
# Common service discovery issues
470
error_str = str(e).lower()
471
if "not performed" in error_str:
472
print("Service discovery was not completed during connection")
473
elif "timeout" in error_str:
474
print("Service discovery timed out - device may be slow to respond")
475
476
except BleakError as e:
477
print(f"Connection or service discovery error: {e}")
478
479
asyncio.run(safe_service_discovery())
480
```
481
482
## Types
483
484
```python { .api }
485
# Error code mappings (partial - full mappings in bleak.exc)
486
CONTROLLER_ERROR_CODES: dict[int, str]
487
PROTOCOL_ERROR_CODES: dict[int, str]
488
489
# Exception hierarchy
490
class BleakError(Exception): ...
491
class BleakCharacteristicNotFoundError(BleakError): ...
492
class BleakDeviceNotFoundError(BleakError): ...
493
class BleakDBusError(BleakError): ...
494
```