or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdclient-management.mdconfiguration.mdexception-handling.mdhttp-clients.mdindex.mdresponse-handling.mdspec-loading.mdtesting-utilities.md

exception-handling.mddocs/

0

# Exception Handling

1

2

Complete HTTP status code exception hierarchy with timeout and connection error handling. Bravado provides specific exceptions for all HTTP status codes plus bravado-specific errors, enabling precise error handling for robust applications.

3

4

## Capabilities

5

6

### HTTPError (Base Exception)

7

8

Unified HTTP error base class that all HTTP-related exceptions inherit from. Contains response data and optional swagger result.

9

10

```python { .api }

11

class HTTPError(IOError):

12

status_code: int

13

def __init__(self, response, message: str = None, swagger_result=None): ...

14

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

15

```

16

17

**Attributes:**

18

- `status_code` (int): HTTP status code associated with this exception type

19

- `response`: IncomingResponse object containing the HTTP response details

20

- `message` (str): Optional custom error message

21

- `swagger_result`: Parsed response data if available

22

23

**Usage Example:**

24

25

```python

26

from bravado.exception import HTTPError, HTTPNotFound

27

28

try:

29

pet = client.pet.getPetById(petId=999).response().result

30

except HTTPNotFound as e:

31

print(f"Pet not found: {e}")

32

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

33

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

34

except HTTPError as e:

35

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

36

```

37

38

### Exception Hierarchy

39

40

Bravado organizes HTTP exceptions into logical categories:

41

42

#### HTTPRedirection (3xx)

43

44

Base class for 3xx redirection responses.

45

46

```python { .api }

47

class HTTPRedirection(HTTPError): ...

48

```

49

50

**Specific 3xx Exceptions:**

51

- `HTTPMultipleChoices` (300)

52

- `HTTPMovedPermanently` (301)

53

- `HTTPFound` (302)

54

- `HTTPSeeOther` (303)

55

- `HTTPNotModified` (304)

56

- `HTTPUseProxy` (305)

57

- `HTTPTemporaryRedirect` (307)

58

- `HTTPPermanentRedirect` (308)

59

60

#### HTTPClientError (4xx)

61

62

Base class for 4xx client error responses.

63

64

```python { .api }

65

class HTTPClientError(HTTPError): ...

66

```

67

68

**Common 4xx Exceptions:**

69

- `HTTPBadRequest` (400) - Invalid request syntax or parameters

70

- `HTTPUnauthorized` (401) - Authentication required or failed

71

- `HTTPPaymentRequired` (402) - Payment required

72

- `HTTPForbidden` (403) - Access denied

73

- `HTTPNotFound` (404) - Resource not found

74

- `HTTPMethodNotAllowed` (405) - HTTP method not supported

75

- `HTTPNotAcceptable` (406) - Cannot produce acceptable response

76

- `HTTPRequestTimeout` (408) - Request timeout

77

- `HTTPConflict` (409) - Request conflicts with current state

78

- `HTTPGone` (410) - Resource permanently removed

79

- `HTTPUnprocessableEntity` (422) - Validation errors

80

- `HTTPTooManyRequests` (429) - Rate limit exceeded

81

82

**All 4xx Exceptions:**

83

```python { .api }

84

class HTTPBadRequest(HTTPClientError): status_code = 400

85

class HTTPUnauthorized(HTTPClientError): status_code = 401

86

class HTTPPaymentRequired(HTTPClientError): status_code = 402

87

class HTTPForbidden(HTTPClientError): status_code = 403

88

class HTTPNotFound(HTTPClientError): status_code = 404

89

class HTTPMethodNotAllowed(HTTPClientError): status_code = 405

90

class HTTPNotAcceptable(HTTPClientError): status_code = 406

91

class HTTPProxyAuthenticationRequired(HTTPClientError): status_code = 407

92

class HTTPRequestTimeout(HTTPClientError): status_code = 408

93

class HTTPConflict(HTTPClientError): status_code = 409

94

class HTTPGone(HTTPClientError): status_code = 410

95

class HTTPLengthRequired(HTTPClientError): status_code = 411

96

class HTTPPreconditionFailed(HTTPClientError): status_code = 412

97

class HTTPPayloadTooLarge(HTTPClientError): status_code = 413

98

class HTTPURITooLong(HTTPClientError): status_code = 414

99

class HTTPUnsupportedMediaType(HTTPClientError): status_code = 415

100

class HTTPRangeNotSatisfiable(HTTPClientError): status_code = 416

101

class HTTPExpectationFailed(HTTPClientError): status_code = 417

102

class HTTPMisdirectedRequest(HTTPClientError): status_code = 421

103

class HTTPUnprocessableEntity(HTTPClientError): status_code = 422

104

class HTTPLocked(HTTPClientError): status_code = 423

105

class HTTPFailedDependency(HTTPClientError): status_code = 424

106

class HTTPUpgradeRequired(HTTPClientError): status_code = 426

107

class HTTPPreconditionRequired(HTTPClientError): status_code = 428

108

class HTTPTooManyRequests(HTTPClientError): status_code = 429

109

class HTTPRequestHeaderFieldsTooLarge(HTTPClientError): status_code = 431

110

class HTTPUnavailableForLegalReasons(HTTPClientError): status_code = 451

111

```

112

113

#### HTTPServerError (5xx)

114

115

Base class for 5xx server error responses. Includes response text in string representation for debugging.

116

117

```python { .api }

118

class HTTPServerError(HTTPError): ...

119

```

120

121

**Common 5xx Exceptions:**

122

- `HTTPInternalServerError` (500) - Server internal error

123

- `HTTPNotImplemented` (501) - Server does not support functionality

124

- `HTTPBadGateway` (502) - Invalid response from upstream server

125

- `HTTPServiceUnavailable` (503) - Server temporarily unavailable

126

- `HTTPGatewayTimeout` (504) - Upstream server timeout

127

- `HTTPHTTPVersionNotSupported` (505) - HTTP version not supported

128

129

**All 5xx Exceptions:**

130

```python { .api }

131

class HTTPInternalServerError(HTTPServerError): status_code = 500

132

class HTTPNotImplemented(HTTPServerError): status_code = 501

133

class HTTPBadGateway(HTTPServerError): status_code = 502

134

class HTTPServiceUnavailable(HTTPServerError): status_code = 503

135

class HTTPGatewayTimeout(HTTPServerError): status_code = 504

136

class HTTPHTTPVersionNotSupported(HTTPServerError): status_code = 505

137

class HTTPVariantAlsoNegotiates(HTTPServerError): status_code = 506

138

class HTTPInsufficientStorage(HTTPServerError): status_code = 507

139

class HTTPLoopDetected(HTTPServerError): status_code = 508

140

class HTTPNotExtended(HTTPServerError): status_code = 510

141

class HTTPNetworkAuthenticationRequired(HTTPServerError): status_code = 511

142

```

143

144

### Connection and Transport Errors

145

146

Bravado-specific exceptions for connection and transport-level issues.

147

148

```python { .api }

149

class BravadoTimeoutError(TimeoutError): ...

150

class BravadoConnectionError(ConnectionError): ...

151

class ForcedFallbackResultError(Exception): ...

152

```

153

154

**BravadoTimeoutError**: Raised when requests exceed configured timeout values.

155

**BravadoConnectionError**: Raised when connection to the server cannot be established.

156

**ForcedFallbackResultError**: Used internally to force fallback result behavior.

157

158

### Exception Factory Function

159

160

Utility function to create appropriate HTTP exceptions from responses.

161

162

```python { .api }

163

def make_http_exception(response, message: str = None, swagger_result=None) -> HTTPError: ...

164

```

165

166

**Parameters:**

167

- `response`: IncomingResponse object

168

- `message` (str): Optional custom error message

169

- `swagger_result`: Parsed response data if available

170

171

**Returns:**

172

- Appropriate HTTPError subclass instance based on status code

173

174

**Usage Example:**

175

176

```python

177

from bravado.exception import make_http_exception

178

179

# Manually create exception from response

180

try:

181

# ... some HTTP operation

182

pass

183

except Exception as e:

184

if hasattr(e, 'response'):

185

http_exception = make_http_exception(e.response, "Custom error message")

186

raise http_exception

187

```

188

189

### Status Code Mapping

190

191

All HTTP status codes are mapped to their corresponding exception classes:

192

193

```python { .api }

194

status_map: dict # Mapping of int status codes to exception classes

195

```

196

197

This dictionary maps HTTP status codes to their corresponding exception classes and is used internally by the exception factory.

198

199

## Error Handling Patterns

200

201

### Basic Exception Handling

202

203

```python

204

from bravado.exception import HTTPClientError, HTTPServerError, BravadoTimeoutError

205

206

try:

207

response = client.pet.getPetById(petId=1).response()

208

pet = response.result

209

except HTTPClientError as e:

210

if e.status_code == 404:

211

print("Pet not found")

212

elif e.status_code == 401:

213

print("Authentication required")

214

else:

215

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

216

except HTTPServerError as e:

217

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

218

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

219

except BravadoTimeoutError:

220

print("Request timed out")

221

```

222

223

### Specific Status Code Handling

224

225

```python

226

from bravado.exception import HTTPNotFound, HTTPUnauthorized, HTTPTooManyRequests

227

import time

228

229

try:

230

response = client.pet.getPetById(petId=1).response()

231

pet = response.result

232

except HTTPNotFound:

233

print("Pet does not exist")

234

pet = None

235

except HTTPUnauthorized:

236

print("Need to refresh authentication")

237

# Handle re-authentication

238

except HTTPTooManyRequests as e:

239

# Handle rate limiting

240

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

241

print(f"Rate limited, waiting {retry_after} seconds")

242

time.sleep(retry_after)

243

# Retry logic here

244

```

245

246

### Validation Error Handling

247

248

```python

249

from bravado.exception import HTTPBadRequest, HTTPUnprocessableEntity

250

251

try:

252

response = client.pet.addPet(body=new_pet_data).response()

253

pet = response.result

254

except HTTPBadRequest as e:

255

print("Invalid request format")

256

print(f"Error details: {e.response.text}")

257

except HTTPUnprocessableEntity as e:

258

print("Validation failed")

259

# Parse validation errors from response

260

errors = e.response.json().get('errors', [])

261

for error in errors:

262

print(f"Field {error['field']}: {error['message']}")

263

```

264

265

### Fallback with Exception Handling

266

267

```python

268

from bravado.exception import HTTPServerError, BravadoTimeoutError

269

270

# Combine fallback results with specific exception handling

271

try:

272

response = client.pet.getPetById(petId=1).response(

273

timeout=5.0,

274

fallback_result={'name': 'Unknown', 'status': 'unavailable'},

275

exceptions_to_catch=(BravadoTimeoutError, HTTPServerError)

276

)

277

278

if response.metadata.is_fallback_result:

279

print("Using fallback data due to service issues")

280

# Handle degraded functionality

281

282

pet = response.result

283

284

except HTTPNotFound:

285

# Still handle specific client errors that shouldn't use fallback

286

print("Pet definitely does not exist")

287

pet = None

288

```

289

290

### Logging and Monitoring

291

292

```python

293

import logging

294

from bravado.exception import HTTPError

295

296

logger = logging.getLogger(__name__)

297

298

try:

299

response = client.pet.getPetById(petId=1).response()

300

pet = response.result

301

except HTTPError as e:

302

# Log detailed error information for monitoring

303

logger.error(

304

"HTTP error in getPetById",

305

extra={

306

'status_code': e.status_code,

307

'pet_id': 1,

308

'response_body': e.response.text[:1000], # Truncate for logging

309

'response_headers': dict(e.response.headers),

310

}

311

)

312

raise # Re-raise for upstream handling

313

```

314

315

## Best Practices

316

317

1. **Catch Specific Exceptions**: Use specific exception types rather than generic HTTPError when possible

318

2. **Handle Expected Errors**: Plan for common API errors like 404, 401, 429

319

3. **Log Error Details**: Include status codes, response bodies, and request context in logs

320

4. **Use Fallback Results**: Consider fallback results for non-critical operations

321

5. **Retry Logic**: Implement appropriate retry logic for transient errors (5xx, timeouts)

322

6. **Rate Limiting**: Respect rate limit headers and implement backoff strategies

323

324

```python

325

# Good exception handling example

326

from bravado.exception import (

327

HTTPNotFound, HTTPUnauthorized, HTTPTooManyRequests,

328

HTTPServerError, BravadoTimeoutError

329

)

330

import time

331

import random

332

333

def get_pet_with_retry(client, pet_id, max_retries=3):

334

for attempt in range(max_retries + 1):

335

try:

336

response = client.pet.getPetById(petId=pet_id).response(timeout=10.0)

337

return response.result

338

339

except HTTPNotFound:

340

return None # Pet doesn't exist, don't retry

341

342

except HTTPUnauthorized:

343

# Handle re-authentication

344

refresh_auth(client)

345

continue

346

347

except HTTPTooManyRequests as e:

348

if attempt < max_retries:

349

# Exponential backoff with jitter

350

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

351

time.sleep(delay)

352

continue

353

raise

354

355

except (HTTPServerError, BravadoTimeoutError) as e:

356

if attempt < max_retries:

357

# Retry transient errors

358

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

359

time.sleep(delay)

360

continue

361

raise

362

363

raise Exception(f"Failed to get pet {pet_id} after {max_retries} retries")

364

```