or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconfiguration.mdexceptions.mdindex.mdpaging.mdpipeline.mdpolling.mdserialization.mdservice-client.md

exceptions.mddocs/

0

# Exception Handling

1

2

Comprehensive error handling with specialized exception types for validation errors, HTTP operation failures, authentication issues, and client request problems. The exception system provides detailed error information and supports proper error handling patterns.

3

4

## Capabilities

5

6

### Base Exception

7

8

Base exception class for all MSRest client runtime errors.

9

10

```python { .api }

11

class ClientException(Exception):

12

def __init__(self, message: str, inner_exception=None, *args, **kwargs):

13

"""

14

Base client exception.

15

16

Parameters:

17

- message: Error description

18

- inner_exception: Nested exception (optional)

19

- args: Additional positional arguments

20

- kwargs: Additional keyword arguments

21

"""

22

23

inner_exception: any

24

```

25

26

### Validation Errors

27

28

Errors that occur during request parameter validation.

29

30

```python { .api }

31

class ValidationError(ClientException):

32

def __init__(self, rule: str, target: str, value: str, *args, **kwargs):

33

"""

34

Request parameter validation error.

35

36

Parameters:

37

- rule: Validation rule that failed

38

- target: Parameter name that failed validation

39

- value: Invalid value that caused the error

40

- args: Additional arguments

41

- kwargs: Additional keyword arguments

42

"""

43

44

rule: str # Validation rule (e.g., 'required', 'min_length')

45

target: str # Parameter name

46

47

# Validation rule messages

48

_messages: dict = {

49

"min_length": "must have length greater than {!r}.",

50

"max_length": "must have length less than {!r}.",

51

"minimum_ex": "must be greater than {!r}.",

52

"maximum_ex": "must be less than {!r}.",

53

"minimum": "must be equal to or greater than {!r}.",

54

"maximum": "must be equal to or less than {!r}.",

55

"min_items": "must contain at least {!r} items.",

56

"max_items": "must contain at most {!r} items.",

57

"pattern": "must conform to the following pattern: {!r}.",

58

"unique": "must contain only unique items.",

59

"multiple": "must be a multiple of {!r}.",

60

"required": "can not be None.",

61

"type": "must be of type {!r}"

62

}

63

```

64

65

### HTTP Operation Errors

66

67

Errors that occur during HTTP operations with detailed response information.

68

69

```python { .api }

70

class HttpOperationError(ClientException):

71

def __init__(self, deserialize, response, resp_type=None, *args, **kwargs):

72

"""

73

HTTP operation error with response details.

74

75

Parameters:

76

- deserialize: Deserializer for error response

77

- response: HTTP response object

78

- resp_type: Expected response type for deserialization

79

- args: Additional arguments

80

- kwargs: Additional keyword arguments

81

"""

82

83

error: any # Deserialized error object

84

message: str # Error message

85

response: any # HTTP response object

86

87

_DEFAULT_MESSAGE: str = "Unknown error"

88

```

89

90

### Authentication Errors

91

92

Errors related to authentication and authorization.

93

94

```python { .api }

95

class AuthenticationError(ClientException):

96

"""Client request failed to authenticate."""

97

98

class TokenExpiredError(ClientException):

99

"""OAuth token expired, request failed."""

100

```

101

102

### Client Request Errors

103

104

General client request failures.

105

106

```python { .api }

107

class ClientRequestError(ClientException):

108

"""Client request failed."""

109

```

110

111

### Serialization Errors

112

113

Errors during data serialization and deserialization (imported from azure.core).

114

115

```python { .api }

116

# Imported from azure.core.exceptions

117

class SerializationError(Exception):

118

"""Error during data serialization."""

119

120

class DeserializationError(Exception):

121

"""Error during data deserialization."""

122

```

123

124

### Utility Functions

125

126

Helper functions for exception handling.

127

128

```python { .api }

129

def raise_with_traceback(exception, message="", *args, **kwargs):

130

"""

131

Raise exception preserving original traceback.

132

Must be called within an except block.

133

134

Parameters:

135

- exception: Exception class to raise

136

- message: Error message

137

- args: Additional arguments for exception

138

- kwargs: Additional keyword arguments for exception

139

"""

140

```

141

142

## Usage Examples

143

144

### Basic Exception Handling

145

146

```python

147

from msrest import ServiceClient, Configuration

148

from msrest.exceptions import (

149

ClientException, ValidationError, HttpOperationError,

150

AuthenticationError, ClientRequestError

151

)

152

153

config = Configuration(base_url='https://api.example.com')

154

client = ServiceClient(None, config)

155

156

try:

157

request = client.get('/data')

158

response = client.send(request)

159

160

except AuthenticationError as e:

161

print(f"Authentication failed: {e}")

162

# Handle authentication error (e.g., refresh token)

163

164

except HttpOperationError as e:

165

print(f"HTTP operation failed: {e}")

166

print(f"Status code: {e.response.status_code}")

167

print(f"Response body: {e.response.text}")

168

169

except ClientRequestError as e:

170

print(f"Client request error: {e}")

171

172

except ClientException as e:

173

print(f"General client error: {e}")

174

if e.inner_exception:

175

print(f"Inner exception: {e.inner_exception}")

176

```

177

178

### Validation Error Handling

179

180

```python

181

from msrest.serialization import Serializer

182

from msrest.exceptions import ValidationError

183

184

serializer = Serializer()

185

186

try:

187

# This will fail validation

188

result = serializer.url('user_id', None, 'int', required=True)

189

190

except ValidationError as e:

191

print(f"Validation failed for parameter '{e.target}'")

192

print(f"Rule: {e.rule}")

193

print(f"Message: {e}")

194

195

# Handle specific validation rules

196

if e.rule == 'required':

197

print("Parameter is required but was None")

198

elif e.rule == 'min_length':

199

print("Value is too short")

200

elif e.rule == 'pattern':

201

print("Value doesn't match required pattern")

202

```

203

204

### HTTP Error Response Handling

205

206

```python

207

from msrest.exceptions import HttpOperationError

208

from msrest.serialization import Deserializer

209

import json

210

211

def handle_api_errors(client, request):

212

"""Handle various HTTP error responses."""

213

214

try:

215

response = client.send(request)

216

return response

217

218

except HttpOperationError as e:

219

status_code = e.response.status_code

220

221

# Handle specific status codes

222

if status_code == 400:

223

print("Bad Request - check request parameters")

224

# Try to parse error details

225

try:

226

error_data = json.loads(e.response.text)

227

print(f"Error details: {error_data}")

228

except json.JSONDecodeError:

229

print(f"Raw error response: {e.response.text}")

230

231

elif status_code == 401:

232

print("Unauthorized - authentication required")

233

raise AuthenticationError("Authentication required")

234

235

elif status_code == 403:

236

print("Forbidden - insufficient permissions")

237

238

elif status_code == 404:

239

print("Not Found - resource doesn't exist")

240

241

elif status_code == 429:

242

print("Rate Limited - too many requests")

243

# Could implement retry with backoff

244

245

elif status_code >= 500:

246

print(f"Server Error ({status_code}) - service unavailable")

247

# Could implement retry logic

248

249

else:

250

print(f"Unexpected HTTP error: {status_code}")

251

252

# Re-raise the original exception

253

raise

254

255

# Usage

256

try:

257

response = handle_api_errors(client, request)

258

except Exception as e:

259

print(f"Request ultimately failed: {e}")

260

```

261

262

### Custom Exception Classes

263

264

```python

265

from msrest.exceptions import ClientException

266

267

class CustomAPIError(ClientException):

268

"""Custom exception for specific API errors."""

269

270

def __init__(self, error_code, error_message, response=None):

271

super(CustomAPIError, self).__init__(error_message)

272

self.error_code = error_code

273

self.response = response

274

275

class RateLimitError(CustomAPIError):

276

"""Rate limiting error with retry information."""

277

278

def __init__(self, retry_after=None, response=None):

279

message = f"Rate limit exceeded"

280

if retry_after:

281

message += f", retry after {retry_after} seconds"

282

283

super(RateLimitError, self).__init__("RATE_LIMIT", message, response)

284

self.retry_after = retry_after

285

286

# Usage with custom exceptions

287

def make_api_request(client, request):

288

try:

289

response = client.send(request)

290

return response

291

292

except HttpOperationError as e:

293

if e.response.status_code == 429:

294

# Extract retry-after header

295

retry_after = e.response.headers.get('Retry-After')

296

if retry_after:

297

retry_after = int(retry_after)

298

raise RateLimitError(retry_after, e.response)

299

300

# Check for custom API error format

301

try:

302

error_data = json.loads(e.response.text)

303

if 'error_code' in error_data:

304

raise CustomAPIError(

305

error_data['error_code'],

306

error_data.get('error_message', 'Unknown error'),

307

e.response

308

)

309

except (json.JSONDecodeError, KeyError):

310

pass

311

312

# Re-raise original exception if not handled

313

raise

314

315

# Handle custom exceptions

316

try:

317

response = make_api_request(client, request)

318

except RateLimitError as e:

319

print(f"Rate limited: {e}")

320

if e.retry_after:

321

print(f"Can retry after {e.retry_after} seconds")

322

except CustomAPIError as e:

323

print(f"API Error {e.error_code}: {e}")

324

```

325

326

### Serialization Error Handling

327

328

```python

329

from msrest.serialization import Serializer, Deserializer, Model

330

from msrest.exceptions import SerializationError, DeserializationError

331

332

class User(Model):

333

_attribute_map = {

334

'name': {'key': 'name', 'type': 'str'},

335

'age': {'key': 'age', 'type': 'int'}

336

}

337

338

serializer = Serializer({'User': User})

339

deserializer = Deserializer({'User': User})

340

341

# Serialization error handling

342

try:

343

# This might fail if data is invalid

344

user_data = {'name': 'John', 'age': 'invalid_age'}

345

serialized = serializer.body(user_data, 'User')

346

347

except SerializationError as e:

348

print(f"Serialization failed: {e}")

349

# Could try data type conversion or validation

350

351

# Deserialization error handling

352

try:

353

# This might fail with invalid JSON or missing fields

354

response_text = '{"name": "John", "age": "not_a_number"}'

355

user = deserializer('User', response_text)

356

357

except DeserializationError as e:

358

print(f"Deserialization failed: {e}")

359

# Could implement fallback parsing or error recovery

360

```

361

362

### Exception Context and Traceback

363

364

```python

365

import sys

366

import traceback

367

from msrest.exceptions import raise_with_traceback, ClientException

368

369

def process_with_context():

370

"""Demonstrate exception handling with context preservation."""

371

372

try:

373

# Some operation that might fail

374

result = risky_operation()

375

return result

376

377

except ValueError as e:

378

# Preserve original traceback while raising different exception

379

try:

380

raise_with_traceback(

381

ClientException,

382

f"Processing failed: {e}",

383

inner_exception=e

384

)

385

except Exception:

386

# If raise_with_traceback fails, raise normally

387

raise ClientException(f"Processing failed: {e}", inner_exception=e)

388

389

except Exception as e:

390

# Log full traceback for debugging

391

print("Unexpected error occurred:")

392

traceback.print_exc()

393

394

# Create exception with context

395

exc_type, exc_value, exc_traceback = sys.exc_info()

396

raise ClientException(

397

f"Unexpected error: {exc_type.__name__}: {exc_value}",

398

inner_exception=e

399

)

400

401

# Usage

402

try:

403

result = process_with_context()

404

except ClientException as e:

405

print(f"Process failed: {e}")

406

if e.inner_exception:

407

print(f"Root cause: {type(e.inner_exception).__name__}: {e.inner_exception}")

408

```

409

410

### Comprehensive Error Handling Strategy

411

412

```python

413

import time

414

import logging

415

from msrest.exceptions import *

416

417

# Configure logging for error tracking

418

logging.basicConfig(level=logging.INFO)

419

logger = logging.getLogger(__name__)

420

421

class APIClient:

422

"""Client with comprehensive error handling."""

423

424

def __init__(self, client):

425

self.client = client

426

self.max_retries = 3

427

self.base_retry_delay = 1

428

429

def make_request(self, request, **kwargs):

430

"""Make request with full error handling and retry logic."""

431

432

last_exception = None

433

434

for attempt in range(self.max_retries + 1):

435

try:

436

response = self.client.send(request, **kwargs)

437

438

# Success

439

logger.info(f"Request successful on attempt {attempt + 1}")

440

return response

441

442

except ValidationError as e:

443

# Validation errors are not retryable

444

logger.error(f"Validation error: {e}")

445

raise

446

447

except AuthenticationError as e:

448

# Authentication errors might be retryable if token can be refreshed

449

logger.warning(f"Authentication error: {e}")

450

if attempt < self.max_retries:

451

logger.info("Attempting to refresh authentication")

452

# Implement token refresh logic here

453

time.sleep(1)

454

continue

455

raise

456

457

except HttpOperationError as e:

458

status_code = e.response.status_code

459

460

# Client errors (4xx) - generally not retryable

461

if 400 <= status_code < 500:

462

if status_code == 429: # Rate limit - retryable

463

retry_after = e.response.headers.get('Retry-After', self.base_retry_delay)

464

if attempt < self.max_retries:

465

logger.warning(f"Rate limited, retrying after {retry_after}s")

466

time.sleep(int(retry_after))

467

continue

468

469

logger.error(f"Client error ({status_code}): {e}")

470

raise

471

472

# Server errors (5xx) - retryable

473

elif status_code >= 500:

474

if attempt < self.max_retries:

475

delay = self.base_retry_delay * (2 ** attempt) # Exponential backoff

476

logger.warning(f"Server error ({status_code}), retrying in {delay}s")

477

time.sleep(delay)

478

last_exception = e

479

continue

480

481

logger.error(f"Server error after {self.max_retries} retries: {e}")

482

raise

483

484

else:

485

logger.error(f"Unexpected HTTP status {status_code}: {e}")

486

raise

487

488

except ClientRequestError as e:

489

# Network/connection errors - retryable

490

if attempt < self.max_retries:

491

delay = self.base_retry_delay * (2 ** attempt)

492

logger.warning(f"Request error, retrying in {delay}s: {e}")

493

time.sleep(delay)

494

last_exception = e

495

continue

496

497

logger.error(f"Request failed after {self.max_retries} retries: {e}")

498

raise

499

500

except ClientException as e:

501

# General client exceptions

502

logger.error(f"Client exception: {e}")

503

if e.inner_exception:

504

logger.error(f"Inner exception: {e.inner_exception}")

505

raise

506

507

except Exception as e:

508

# Unexpected errors

509

logger.error(f"Unexpected error: {type(e).__name__}: {e}")

510

raise ClientException(f"Unexpected error: {e}", inner_exception=e)

511

512

# All retries exhausted

513

if last_exception:

514

raise last_exception

515

516

# Usage

517

api_client = APIClient(client)

518

519

try:

520

request = client.get('/api/data')

521

response = api_client.make_request(request)

522

print("Request successful")

523

524

except ValidationError as e:

525

print(f"Invalid request parameters: {e}")

526

except AuthenticationError as e:

527

print(f"Authentication failed: {e}")

528

except HttpOperationError as e:

529

print(f"HTTP operation failed: {e}")

530

except ClientException as e:

531

print(f"Client error: {e}")

532

except Exception as e:

533

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

534

```

535

536

## Exception Hierarchy

537

538

```

539

Exception

540

└── ClientException

541

├── ValidationError

542

├── ClientRequestError

543

├── AuthenticationError

544

│ └── TokenExpiredError

545

└── HttpOperationError

546

```

547

548

## Error Response Formats

549

550

Common error response formats that HttpOperationError can deserialize:

551

552

```python

553

# OData v4 format (used by Azure ARM)

554

{

555

"error": {

556

"code": "ResourceNotFound",

557

"message": "The requested resource was not found"

558

}

559

}

560

561

# Simple format

562

{

563

"message": "Validation failed for field 'email'"

564

}

565

566

# Detailed format

567

{

568

"error_code": "INVALID_INPUT",

569

"error_message": "Email address is required",

570

"details": {

571

"field": "email",

572

"value": null

573

}

574

}

575

```