or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-programming-patterns.mdauthentication-and-credentials.mdconfiguration-and-settings.mddistributed-tracing-and-diagnostics.mderror-handling-and-exceptions.mdhttp-pipeline-and-policies.mdindex.mdpaging-and-result-iteration.mdpolling-and-long-running-operations.mdrest-api-abstraction.mdtransport-and-networking.mdutilities-and-helpers.md

error-handling-and-exceptions.mddocs/

0

# Error Handling and Exceptions

1

2

Azure Core provides a comprehensive exception hierarchy designed to handle various error conditions that can occur when interacting with Azure services. The exception system enables consistent error handling across all Azure SDK clients.

3

4

## Core Exception Hierarchy

5

6

All Azure Core exceptions inherit from the base `AzureError` class, providing a consistent interface for error handling.

7

8

```python { .api }

9

from azure.core.exceptions import AzureError

10

11

class AzureError(Exception):

12

"""Base exception for all Azure SDK errors."""

13

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

14

15

@property

16

def message(self) -> str: ...

17

18

@property

19

def error(self) -> Optional[object]: ...

20

21

@property

22

def continuation_token(self) -> Optional[str]: ...

23

```

24

25

## Capabilities

26

27

### Service Request and Response Errors

28

29

Errors that occur during HTTP request preparation and response processing.

30

31

```python { .api }

32

from azure.core.exceptions import ServiceRequestError, ServiceResponseError, HttpResponseError

33

34

class ServiceRequestError(AzureError):

35

"""Error occurred during request preparation."""

36

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

37

38

class ServiceResponseError(AzureError):

39

"""Error occurred during response processing."""

40

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

41

42

class HttpResponseError(AzureError):

43

"""HTTP response error with status code information."""

44

def __init__(self, message: str = None, response: HttpResponse = None, **kwargs): ...

45

46

@property

47

def status_code(self) -> Optional[int]: ...

48

49

@property

50

def response(self) -> Optional[HttpResponse]: ...

51

52

@property

53

def reason(self) -> Optional[str]: ...

54

```

55

56

### HTTP Status Code Specific Errors

57

58

Specialized exceptions for common HTTP status codes and error conditions.

59

60

```python { .api }

61

from azure.core.exceptions import (

62

ResourceExistsError, ResourceNotFoundError, ResourceModifiedError,

63

ResourceNotModifiedError, ClientAuthenticationError

64

)

65

66

class ResourceExistsError(HttpResponseError):

67

"""Resource already exists error (typically 409)."""

68

pass

69

70

class ResourceNotFoundError(HttpResponseError):

71

"""Resource not found error (404/412)."""

72

pass

73

74

class ResourceModifiedError(HttpResponseError):

75

"""Resource was modified error (412 with etag mismatch)."""

76

pass

77

78

class ResourceNotModifiedError(HttpResponseError):

79

"""Resource not modified error (304)."""

80

pass

81

82

class ClientAuthenticationError(HttpResponseError):

83

"""Authentication error (401/403)."""

84

pass

85

```

86

87

### Network and Transport Errors

88

89

Errors related to network connectivity and HTTP transport.

90

91

```python { .api }

92

from azure.core.exceptions import (

93

TooManyRedirectsError, ServiceRequestTimeoutError, ServiceResponseTimeoutError,

94

IncompleteReadError

95

)

96

97

class TooManyRedirectsError(ServiceRequestError):

98

"""Maximum redirect attempts exceeded."""

99

def __init__(self, history: Optional[List] = None, **kwargs): ...

100

101

@property

102

def history(self) -> Optional[List]: ...

103

104

class ServiceRequestTimeoutError(ServiceRequestError):

105

"""Service request timeout error."""

106

pass

107

108

class ServiceResponseTimeoutError(ServiceResponseError):

109

"""Service response timeout error."""

110

pass

111

112

class IncompleteReadError(ServiceResponseError):

113

"""Incomplete read error during response processing."""

114

pass

115

```

116

117

### Stream and Content Errors

118

119

Errors related to request/response stream handling and content processing.

120

121

```python { .api }

122

from azure.core.exceptions import (

123

StreamConsumedError, StreamClosedError, ResponseNotReadError

124

)

125

126

class StreamConsumedError(AzureError):

127

"""Stream has already been consumed and cannot be read again."""

128

pass

129

130

class StreamClosedError(AzureError):

131

"""Stream has been closed and cannot be accessed."""

132

pass

133

134

class ResponseNotReadError(AzureError):

135

"""Response content has not been read yet."""

136

pass

137

```

138

139

### Serialization and Deserialization Errors

140

141

Errors that occur during data serialization and deserialization.

142

143

```python { .api }

144

from azure.core.exceptions import SerializationError, DeserializationError, DecodeError

145

146

class SerializationError(AzureError):

147

"""Error occurred during data serialization."""

148

pass

149

150

class DeserializationError(AzureError):

151

"""Error occurred during data deserialization."""

152

pass

153

154

class DecodeError(ServiceResponseError):

155

"""Response content decoding error."""

156

pass

157

```

158

159

### OData Error Handling

160

161

Support for OData V4 error format parsing commonly used by Azure services.

162

163

```python { .api }

164

from azure.core.exceptions import ODataV4Format, ODataV4Error

165

166

class ODataV4Format:

167

"""OData V4 error format parser."""

168

@staticmethod

169

def deserialize(response: HttpResponse) -> Dict: ...

170

171

class ODataV4Error(HttpResponseError):

172

"""OData V4 formatted error response."""

173

def __init__(self, response: HttpResponse, **kwargs): ...

174

175

@property

176

def code(self) -> Optional[str]: ...

177

178

@property

179

def details(self) -> Optional[List[Dict]]: ...

180

```

181

182

### Exception Mapping Utilities

183

184

Utilities for mapping HTTP status codes to appropriate exception types.

185

186

```python { .api }

187

from azure.core.exceptions import map_error

188

from typing import Dict, Type, Callable

189

190

def map_error(

191

status_code: int,

192

response: HttpResponse,

193

error_map: Optional[Dict[int, Type[HttpResponseError]]] = None

194

) -> None:

195

"""Map HTTP status codes to exception types and raise appropriate error."""

196

...

197

198

# Deprecated utility function

199

def raise_with_traceback(exception: Exception, traceback=None) -> None:

200

"""Raise exception with traceback (deprecated)."""

201

...

202

```

203

204

## Usage Examples

205

206

### Basic Exception Handling

207

208

```python

209

from azure.core.exceptions import AzureError, HttpResponseError, ResourceNotFoundError

210

from azure.core import PipelineClient

211

212

try:

213

client = PipelineClient(base_url="https://api.example.com")

214

# Make request...

215

except ResourceNotFoundError as e:

216

print(f"Resource not found: {e.message}")

217

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

218

except HttpResponseError as e:

219

print(f"HTTP error: {e.status_code} - {e.reason}")

220

except AzureError as e:

221

print(f"Azure error: {e.message}")

222

except Exception as e:

223

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

224

```

225

226

### Custom Error Mapping

227

228

```python

229

from azure.core.exceptions import map_error, HttpResponseError

230

231

# Define custom error mapping

232

error_map = {

233

404: ResourceNotFoundError,

234

409: ResourceExistsError,

235

401: ClientAuthenticationError,

236

}

237

238

def handle_response(response):

239

if response.status_code >= 400:

240

# Use custom error mapping

241

map_error(response.status_code, response, error_map)

242

return response

243

```

244

245

### Handling Specific Service Errors

246

247

```python

248

from azure.core.exceptions import HttpResponseError, ODataV4Error

249

import json

250

251

try:

252

# Make service request...

253

pass

254

except HttpResponseError as e:

255

if e.response and e.response.headers.get("content-type", "").startswith("application/json"):

256

try:

257

error_details = e.response.json()

258

if "error" in error_details:

259

# Handle OData error format

260

error_code = error_details["error"].get("code")

261

error_message = error_details["error"].get("message")

262

print(f"Service error {error_code}: {error_message}")

263

else:

264

print(f"Service returned error: {error_details}")

265

except (json.JSONDecodeError, KeyError):

266

print(f"Non-JSON error response: {e.message}")

267

else:

268

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

269

```

270

271

### Retry Logic with Exception Handling

272

273

```python

274

from azure.core.exceptions import AzureError, ServiceRequestError

275

import time

276

import random

277

278

def retry_with_backoff(func, max_retries=3, base_delay=1.0):

279

"""Retry function with exponential backoff."""

280

for attempt in range(max_retries + 1):

281

try:

282

return func()

283

except (ServiceRequestError, ConnectionError) as e:

284

if attempt == max_retries:

285

raise e

286

287

delay = base_delay * (2 ** attempt) + random.uniform(0, 1)

288

print(f"Attempt {attempt + 1} failed, retrying in {delay:.2f}s...")

289

time.sleep(delay)

290

except AzureError:

291

# Don't retry on non-transient Azure errors

292

raise

293

294

# Usage

295

def make_request():

296

# Your request logic here

297

pass

298

299

try:

300

result = retry_with_backoff(make_request, max_retries=5)

301

except AzureError as e:

302

print(f"Request failed after all retries: {e}")

303

```

304

305

### Stream Error Handling

306

307

```python

308

from azure.core.exceptions import StreamConsumedError, StreamClosedError

309

310

def read_stream_safely(response):

311

try:

312

# Read stream content

313

content = response.content

314

return content

315

except StreamConsumedError:

316

print("Stream has already been consumed")

317

return None

318

except StreamClosedError:

319

print("Stream has been closed")

320

return None

321

322

def read_stream_multiple_times(response):

323

"""Example of handling stream consumption."""

324

try:

325

# First read

326

content1 = response.text

327

328

# Second read will fail

329

content2 = response.text

330

331

except StreamConsumedError:

332

print("Cannot read stream multiple times without reopening")

333

# Would need to make a new request to get content again

334

```

335

336

### Async Exception Handling

337

338

```python

339

import asyncio

340

from azure.core.exceptions import AzureError, HttpResponseError

341

342

async def async_request_with_error_handling():

343

try:

344

# Make async request...

345

pass

346

except HttpResponseError as e:

347

print(f"Async HTTP error: {e.status_code}")

348

# Handle specific async error conditions

349

if e.status_code == 429: # Rate limited

350

# Wait before retrying

351

await asyncio.sleep(1)

352

except AzureError as e:

353

print(f"Async Azure error: {e.message}")

354

355

# asyncio.run(async_request_with_error_handling())

356

```

357

358

## Error Response Processing

359

360

### OData V4 Error Format

361

362

Many Azure services return errors in OData V4 format:

363

364

```json

365

{

366

"error": {

367

"code": "InvalidResourceName",

368

"message": "The specified resource name contains invalid characters.",

369

"details": [

370

{

371

"code": "InvalidCharacter",

372

"message": "Character '@' is not allowed in resource names.",

373

"target": "resourceName"

374

}

375

]

376

}

377

}

378

```

379

380

```python

381

from azure.core.exceptions import ODataV4Format

382

383

def parse_odata_error(response):

384

if response.headers.get("content-type", "").startswith("application/json"):

385

error_data = ODataV4Format.deserialize(response)

386

if error_data:

387

main_error = error_data.get("error", {})

388

code = main_error.get("code")

389

message = main_error.get("message")

390

details = main_error.get("details", [])

391

392

print(f"Error code: {code}")

393

print(f"Error message: {message}")

394

for detail in details:

395

print(f"Detail: {detail.get('message')} (target: {detail.get('target')})")

396

```

397

398

## Best Practices

399

400

### Exception Handling Strategy

401

402

- Catch specific exceptions before general ones (most specific first)

403

- Always catch `AzureError` as a fallback for Azure SDK specific errors

404

- Log exception details including status codes and response content when available

405

- Don't ignore exceptions - handle them appropriately or let them bubble up

406

407

### Error Information Extraction

408

409

- Use the `response` property of `HttpResponseError` to access full response details

410

- Check response headers and content for additional error information

411

- Parse JSON error responses for structured error details

412

- Consider the `continuation_token` property for resumable operations

413

414

### Retry and Recovery

415

416

- Only retry on transient errors (network issues, rate limiting, temporary service errors)

417

- Don't retry on authentication errors or client-side validation errors

418

- Implement exponential backoff with jitter for retry logic

419

- Set reasonable maximum retry limits to avoid infinite loops

420

421

### Logging and Monitoring

422

423

- Log all exceptions with sufficient context for debugging

424

- Include request IDs when available for correlation with service logs

425

- Monitor error rates and patterns to identify service issues

426

- Use structured logging for better error analysis and alerting