or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

challenge-response.mdconfiguration.mddevice-discovery.mddevice-interface.mdexceptions.mdindex.mdutilities.md

exceptions.mddocs/

0

# Exception Handling

1

2

Comprehensive error handling with specific exception types for different failure modes including device communication errors, configuration errors, timeout conditions, and input validation failures.

3

4

## Capabilities

5

6

### Exception Hierarchy

7

8

All YubiKey exceptions inherit from the base `YubicoError` class, allowing unified error handling.

9

10

```python { .api }

11

class YubicoError(Exception):

12

"""

13

Base class for all Yubico exceptions.

14

15

All exceptions raised by YubiKey operations inherit from this class,

16

enabling comprehensive error handling with a single except clause.

17

18

Attributes:

19

- reason (str): Human-readable explanation of the error

20

"""

21

22

def __init__(self, reason):

23

"""

24

Initialize exception with error reason.

25

26

Parameters:

27

- reason (str): Explanation of the error

28

"""

29

self.reason = reason

30

31

def __str__(self):

32

"""

33

String representation of the exception.

34

35

Returns:

36

str: Formatted error message with class name and reason

37

"""

38

```

39

40

Base exception usage:

41

42

```python

43

import yubico

44

45

try:

46

yk = yubico.find_yubikey()

47

# Perform YubiKey operations...

48

49

except yubico.yubico_exception.YubicoError as e:

50

print(f"YubiKey error: {e.reason}")

51

# This will catch all YubiKey-related exceptions

52

```

53

54

### Input Validation Exceptions

55

56

Exceptions raised for invalid input parameters and data validation failures.

57

58

```python { .api }

59

class InputError(YubicoError):

60

"""

61

Exception raised for input validation errors.

62

63

Raised when function parameters fail validation, such as incorrect

64

data types, invalid lengths, or out-of-range values.

65

"""

66

67

def __init__(self, reason='input validation error'):

68

"""

69

Initialize input error exception.

70

71

Parameters:

72

- reason (str): Specific validation error description

73

"""

74

```

75

76

Input validation example:

77

78

```python

79

import yubico

80

from yubico.yubikey_config import YubiKeyConfig

81

82

try:

83

cfg = YubiKeyConfig()

84

85

# Invalid AES key length (must be 16 bytes)

86

cfg.aes_key(b"short_key")

87

88

except yubico.yubico_exception.InputError as e:

89

print(f"Input validation error: {e.reason}")

90

91

try:

92

yk = yubico.find_yubikey()

93

94

# Invalid challenge length for OTP mode (must be 6 bytes)

95

response = yk.challenge(b"too_long_challenge", mode='OTP')

96

97

except yubico.yubico_exception.InputError as e:

98

print(f"Challenge validation error: {e.reason}")

99

```

100

101

### Device Communication Exceptions

102

103

Exceptions related to YubiKey device communication and hardware errors.

104

105

```python { .api }

106

class YubiKeyError(YubicoError):

107

"""

108

Exception raised for YubiKey device operation errors.

109

110

Base class for device-specific errors including communication

111

failures, device not found, and operational errors.

112

"""

113

114

def __init__(self, reason='no details'):

115

"""

116

Initialize YubiKey error.

117

118

Parameters:

119

- reason (str): Error description

120

"""

121

122

class YubiKeyUSBHIDError(YubicoError):

123

"""

124

Exception raised for USB HID communication errors.

125

126

Specific to USB HID transport layer failures, device detection

127

issues, and low-level communication problems.

128

"""

129

```

130

131

Device communication example:

132

133

```python

134

import yubico

135

136

try:

137

yk = yubico.find_yubikey()

138

139

except yubico.yubikey_base.YubiKeyError as e:

140

if "No YubiKey found" in str(e):

141

print("No YubiKey device connected")

142

else:

143

print(f"YubiKey device error: {e.reason}")

144

145

except yubico.yubikey_usb_hid.YubiKeyUSBHIDError as e:

146

print(f"USB communication error: {e.reason}")

147

print("Try unplugging and reconnecting the YubiKey")

148

```

149

150

### Timeout Exceptions

151

152

Exceptions raised when operations exceed time limits or require user interaction.

153

154

```python { .api }

155

class YubiKeyTimeout(YubiKeyError):

156

"""

157

Exception raised when YubiKey operations time out.

158

159

Occurs when operations requiring user interaction (button press)

160

exceed the timeout period, or when device communication stalls.

161

"""

162

163

def __init__(self, reason='no details'):

164

"""

165

Initialize timeout error.

166

167

Parameters:

168

- reason (str): Timeout-specific error description

169

"""

170

```

171

172

Timeout handling example:

173

174

```python

175

import yubico

176

177

yk = yubico.find_yubikey()

178

179

try:

180

# This may timeout if button press is required

181

serial = yk.serial(may_block=True)

182

print(f"Serial number: {serial}")

183

184

except yubico.yubikey_base.YubiKeyTimeout:

185

print("Timeout waiting for user interaction")

186

print("Please touch the YubiKey button when it blinks")

187

188

try:

189

# Challenge-response with button press requirement

190

response = yk.challenge(

191

b"test challenge",

192

mode='HMAC',

193

slot=1,

194

may_block=True

195

)

196

197

except yubico.yubikey_base.YubiKeyTimeout:

198

print("Challenge-response timed out")

199

print("Check if button press is required for this configuration")

200

```

201

202

### Version Compatibility Exceptions

203

204

Exceptions raised when operations are not supported by the connected YubiKey version.

205

206

```python { .api }

207

class YubiKeyVersionError(YubiKeyError):

208

"""

209

Exception raised when YubiKey version doesn't support requested operation.

210

211

Occurs when attempting to use features not available on the connected

212

YubiKey model or firmware version.

213

"""

214

215

def __init__(self, reason='no details'):

216

"""

217

Initialize version error.

218

219

Parameters:

220

- reason (str): Version compatibility error description

221

"""

222

```

223

224

Version compatibility example:

225

226

```python

227

import yubico

228

229

yk = yubico.find_yubikey()

230

print(f"YubiKey version: {yk.version()}")

231

232

try:

233

# Serial number reading requires YubiKey 2.2+

234

serial = yk.serial()

235

print(f"Serial number: {serial}")

236

237

except yubico.yubikey_base.YubiKeyVersionError:

238

print("Serial number reading not supported on this YubiKey version")

239

print("Required: YubiKey 2.2 or later")

240

241

try:

242

# Challenge-response requires YubiKey 2.2+

243

response = yk.challenge_response(b"test", mode='HMAC', slot=1)

244

245

except yubico.yubikey_base.YubiKeyVersionError:

246

print("Challenge-response not supported on this YubiKey version")

247

print("Required: YubiKey 2.2 or later")

248

```

249

250

### Configuration Exceptions

251

252

Exceptions specific to YubiKey configuration operations.

253

254

```python { .api }

255

class YubiKeyConfigError(YubicoError):

256

"""

257

Exception raised for YubiKey configuration errors.

258

259

Occurs when configuration parameters are invalid, incompatible

260

with the target YubiKey, or when configuration write operations fail.

261

"""

262

```

263

264

Configuration error example:

265

266

```python

267

import yubico

268

from yubico.yubikey_config import YubiKeyConfig, YubiKeyConfigError

269

270

try:

271

yk = yubico.find_yubikey()

272

cfg = yk.init_config()

273

274

# Invalid configuration (example)

275

cfg.mode_oath_hotp(b"secret", digits=10) # Invalid digit count

276

277

yk.write_config(cfg, slot=1)

278

279

except YubiKeyConfigError as e:

280

print(f"Configuration error: {e.reason}")

281

282

except yubico.yubikey_base.YubiKeyVersionError as e:

283

print(f"Configuration not supported: {e.reason}")

284

```

285

286

### Comprehensive Error Handling

287

288

Best practices for handling all YubiKey exceptions in applications.

289

290

```python

291

import yubico

292

from yubico.yubikey_config import YubiKeyConfig, YubiKeyConfigError

293

294

def safe_yubikey_operation():

295

"""

296

Demonstrate comprehensive YubiKey error handling.

297

"""

298

try:

299

# Find and connect to YubiKey

300

yk = yubico.find_yubikey(debug=False)

301

print(f"Connected to YubiKey version {yk.version()}")

302

303

# Get device information

304

try:

305

serial = yk.serial(may_block=False)

306

print(f"Serial number: {serial}")

307

except yubico.yubikey_base.YubiKeyVersionError:

308

print("Serial number not available on this YubiKey version")

309

except yubico.yubikey_base.YubiKeyTimeout:

310

print("Serial number requires button press")

311

312

# Attempt challenge-response

313

try:

314

challenge = b"test challenge"

315

response = yk.challenge_response(challenge, slot=1, may_block=False)

316

print(f"Challenge-response successful: {response.hex()}")

317

318

except yubico.yubikey_base.YubiKeyVersionError:

319

print("Challenge-response not supported")

320

except yubico.yubikey_base.YubiKeyTimeout:

321

print("Challenge-response requires button press")

322

except yubico.yubikey_base.YubiKeyError as e:

323

print(f"Challenge-response failed: {e.reason}")

324

325

return True

326

327

except yubico.yubikey_base.YubiKeyError as e:

328

if "No YubiKey found" in str(e):

329

print("ERROR: No YubiKey device connected")

330

else:

331

print(f"ERROR: YubiKey device error: {e.reason}")

332

333

except yubico.yubikey_usb_hid.YubiKeyUSBHIDError as e:

334

print(f"ERROR: USB communication error: {e.reason}")

335

print("Try reconnecting the YubiKey")

336

337

except yubico.yubico_exception.InputError as e:

338

print(f"ERROR: Input validation error: {e.reason}")

339

340

except yubico.yubico_exception.YubicoError as e:

341

print(f"ERROR: General YubiKey error: {e.reason}")

342

343

except Exception as e:

344

print(f"ERROR: Unexpected error: {e}")

345

346

return False

347

348

# Run safe operation

349

success = safe_yubikey_operation()

350

if success:

351

print("YubiKey operations completed successfully")

352

else:

353

print("YubiKey operations failed")

354

```

355

356

### Error Recovery Strategies

357

358

Common strategies for recovering from YubiKey errors.

359

360

```python

361

import yubico

362

import time

363

364

def robust_yubikey_connect(max_retries=3, retry_delay=1.0):

365

"""

366

Robustly connect to YubiKey with retry logic.

367

368

Parameters:

369

- max_retries (int): Maximum connection attempts

370

- retry_delay (float): Delay between retry attempts in seconds

371

372

Returns:

373

YubiKey: Connected YubiKey instance or None

374

"""

375

for attempt in range(max_retries):

376

try:

377

yk = yubico.find_yubikey()

378

print(f"Connected to YubiKey on attempt {attempt + 1}")

379

return yk

380

381

except yubico.yubikey_usb_hid.YubiKeyUSBHIDError:

382

print(f"USB error on attempt {attempt + 1}")

383

if attempt < max_retries - 1:

384

print(f"Retrying in {retry_delay} seconds...")

385

time.sleep(retry_delay)

386

387

except yubico.yubikey_base.YubiKeyError as e:

388

if "No YubiKey found" in str(e):

389

print(f"No YubiKey found on attempt {attempt + 1}")

390

if attempt < max_retries - 1:

391

print("Please connect YubiKey and wait...")

392

time.sleep(retry_delay * 2) # Longer delay for device connection

393

else:

394

print(f"YubiKey error: {e.reason}")

395

break

396

397

print("Failed to connect to YubiKey after all retry attempts")

398

return None

399

400

def handle_timeout_with_retry(operation_func, max_retries=2):

401

"""

402

Handle timeout operations with user guidance.

403

404

Parameters:

405

- operation_func: Function that may timeout

406

- max_retries (int): Maximum retry attempts

407

408

Returns:

409

Result of operation_func or None if all attempts fail

410

"""

411

for attempt in range(max_retries):

412

try:

413

return operation_func()

414

415

except yubico.yubikey_base.YubiKeyTimeout:

416

if attempt < max_retries - 1:

417

print("Operation timed out. Please touch YubiKey button when it blinks.")

418

print("Retrying...")

419

else:

420

print("Operation timed out after all retry attempts")

421

422

return None

423

424

# Usage examples

425

yk = robust_yubikey_connect()

426

if yk:

427

# Retry timeout-prone operations

428

def get_serial():

429

return yk.serial(may_block=True)

430

431

serial = handle_timeout_with_retry(get_serial)

432

if serial:

433

print(f"Serial number: {serial}")

434

```

435

436

### Logging and Debugging

437

438

Enable detailed error information for troubleshooting.

439

440

```python

441

import yubico

442

import logging

443

444

# Enable debug logging

445

logging.basicConfig(level=logging.DEBUG)

446

447

try:

448

# Connect with debug output

449

yk = yubico.find_yubikey(debug=True)

450

451

# Operations will show detailed debug information

452

response = yk.challenge_response(b"debug test", slot=1)

453

454

except yubico.yubico_exception.YubicoError as e:

455

# Log detailed error information

456

logging.error(f"YubiKey operation failed: {e}")

457

logging.error(f"Error type: {type(e).__name__}")

458

logging.error(f"Error reason: {e.reason}")

459

460

# Print exception details for debugging

461

import traceback

462

traceback.print_exc()

463

```