or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-structures.mddevice-discovery.mdexception-handling.mdgatt-client.mdindex.mduuid-utilities.md

exception-handling.mddocs/

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

```