or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdbulk-operations.mdclient-connection.mdcommand-line-interface.mdexceptions.mdindex.mdlow-level-operations.mdutilities.md

exceptions.mddocs/

0

# Exception Handling

1

2

Comprehensive error handling with detailed HTTP context, transaction IDs, and Swift-specific error information.

3

4

## Capabilities

5

6

### ClientException Class

7

8

Main exception class for Swift client operations with comprehensive HTTP context and error details.

9

10

```python { .api }

11

class ClientException(Exception):

12

def __init__(

13

self,

14

msg,

15

http_scheme='',

16

http_host='',

17

http_port='',

18

http_path='',

19

http_query='',

20

http_status=None,

21

http_reason='',

22

http_device='',

23

http_response_content='',

24

http_response_headers=None

25

):

26

"""

27

Swift client exception with HTTP context.

28

29

Parameters:

30

- msg: str, primary error message

31

- http_scheme: str, HTTP scheme (http/https)

32

- http_host: str, HTTP host

33

- http_port: str, HTTP port

34

- http_path: str, HTTP request path

35

- http_query: str, HTTP query string

36

- http_status: int, HTTP status code

37

- http_reason: str, HTTP reason phrase

38

- http_device: str, Swift device identifier

39

- http_response_content: str, HTTP response body

40

- http_response_headers: dict, HTTP response headers

41

42

Attributes:

43

- msg: Primary error message

44

- http_*: HTTP request/response context

45

- transaction_id: Swift transaction ID from response headers

46

"""

47

48

@classmethod

49

def from_response(cls, resp, msg=None, body=None):

50

"""

51

Create ClientException from HTTP response.

52

53

Parameters:

54

- resp: HTTP response object

55

- msg: str, optional custom message (defaults to status and reason)

56

- body: bytes, optional response body (defaults to response content)

57

58

Returns:

59

ClientException: exception with response context

60

"""

61

```

62

63

## Common Exception Scenarios

64

65

### Authentication Errors

66

67

```python

68

# HTTP 401 Unauthorized

69

try:

70

conn = Connection(authurl='...', user='...', key='wrong_password')

71

conn.get_account()

72

except ClientException as e:

73

if e.http_status == 401:

74

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

75

print(f"Check credentials and try again")

76

# e.transaction_id contains Swift transaction ID for debugging

77

```

78

79

### Permission Errors

80

81

```python

82

# HTTP 403 Forbidden

83

try:

84

conn.put_object('restricted_container', 'file.txt', 'content')

85

except ClientException as e:

86

if e.http_status == 403:

87

print(f"Access denied: {e.msg}")

88

print(f"Check account permissions for container")

89

```

90

91

### Not Found Errors

92

93

```python

94

# HTTP 404 Not Found

95

try:

96

headers, content = conn.get_object('nonexistent', 'file.txt')

97

except ClientException as e:

98

if e.http_status == 404:

99

print(f"Object not found: {e.msg}")

100

print(f"Container: {e.http_path.split('/')[-2]}")

101

print(f"Object: {e.http_path.split('/')[-1]}")

102

```

103

104

### Conflict Errors

105

106

```python

107

# HTTP 409 Conflict

108

try:

109

conn.delete_container('container_with_objects')

110

except ClientException as e:

111

if e.http_status == 409:

112

print(f"Cannot delete non-empty container: {e.msg}")

113

print("Delete all objects first, then retry container deletion")

114

```

115

116

### Rate Limiting

117

118

```python

119

# HTTP 498 Rate Limited or HTTP 429 Too Many Requests

120

try:

121

# Rapid operations that might trigger rate limiting

122

for i in range(1000):

123

conn.put_object('container', f'object_{i}', f'content_{i}')

124

except ClientException as e:

125

if e.http_status in (498, 429):

126

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

127

print("Reduce request rate or increase retry backoff")

128

```

129

130

### Server Errors

131

132

```python

133

# HTTP 5xx Server Errors

134

try:

135

conn.get_object('container', 'object')

136

except ClientException as e:

137

if 500 <= e.http_status < 600:

138

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

139

print(f"Transaction ID: {e.transaction_id}")

140

print("Retry the operation or contact Swift administrator")

141

```

142

143

## Usage Examples

144

145

### Comprehensive Error Handling

146

147

```python

148

from swiftclient import Connection, ClientException

149

import time

150

151

def robust_swift_operation(conn, container, obj, content, max_retries=3):

152

"""Perform Swift operation with comprehensive error handling."""

153

154

for attempt in range(max_retries + 1):

155

try:

156

etag = conn.put_object(container, obj, content)

157

print(f"Successfully uploaded {obj} with ETag {etag}")

158

return etag

159

160

except ClientException as e:

161

print(f"Attempt {attempt + 1} failed: {e}")

162

163

if e.http_status == 401:

164

# Authentication error - don't retry

165

print("Authentication failed - check credentials")

166

raise

167

168

elif e.http_status == 403:

169

# Permission error - don't retry

170

print("Access denied - check permissions")

171

raise

172

173

elif e.http_status == 404:

174

# Container doesn't exist - create it and retry

175

print(f"Container '{container}' not found, creating...")

176

try:

177

conn.put_container(container)

178

print(f"Created container '{container}'")

179

continue # Retry the upload

180

except ClientException as create_error:

181

print(f"Failed to create container: {create_error}")

182

raise

183

184

elif e.http_status == 409:

185

# Conflict - might be temporary, retry

186

if attempt < max_retries:

187

wait_time = 2 ** attempt # Exponential backoff

188

print(f"Conflict error, retrying in {wait_time}s...")

189

time.sleep(wait_time)

190

continue

191

else:

192

raise

193

194

elif e.http_status in (498, 429):

195

# Rate limiting - back off and retry

196

if attempt < max_retries:

197

wait_time = 10 * (2 ** attempt) # Longer backoff for rate limits

198

print(f"Rate limited, retrying in {wait_time}s...")

199

time.sleep(wait_time)

200

continue

201

else:

202

raise

203

204

elif e.http_status is None:

205

# Network error

206

if attempt < max_retries:

207

wait_time = 5 * (2 ** attempt)

208

print(f"Network error, retrying in {wait_time}s...")

209

time.sleep(wait_time)

210

continue

211

else:

212

print("Max retries exceeded for network errors")

213

raise

214

215

elif 500 <= e.http_status < 600:

216

# Server error - retry with backoff

217

if attempt < max_retries:

218

wait_time = 3 * (2 ** attempt)

219

print(f"Server error {e.http_status}, retrying in {wait_time}s...")

220

print(f"Transaction ID: {e.transaction_id}")

221

time.sleep(wait_time)

222

continue

223

else:

224

print(f"Max retries exceeded for server error {e.http_status}")

225

print(f"Transaction ID: {e.transaction_id}")

226

raise

227

228

else:

229

# Other HTTP error - don't retry

230

print(f"HTTP {e.http_status} {e.http_reason} - not retrying")

231

raise

232

233

except Exception as e:

234

# Non-HTTP error (programming error, etc.)

235

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

236

raise

237

238

# Should never reach here

239

raise RuntimeError("Maximum retries exceeded")

240

241

# Usage

242

conn = Connection(...)

243

try:

244

robust_swift_operation(conn, 'documents', 'important.txt', 'Important content')

245

except ClientException as e:

246

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

247

```

248

249

### Error Context Analysis

250

251

```python

252

def analyze_swift_error(e):

253

"""Analyze ClientException and provide detailed context."""

254

255

print(f"Error: {e.msg}")

256

print(f"HTTP Status: {e.http_status} {e.http_reason}")

257

258

if e.transaction_id:

259

print(f"Transaction ID: {e.transaction_id}")

260

261

# Reconstruct URL

262

if e.http_scheme and e.http_host:

263

url = f"{e.http_scheme}://{e.http_host}"

264

if e.http_port:

265

url += f":{e.http_port}"

266

if e.http_path:

267

url += e.http_path

268

if e.http_query:

269

url += f"?{e.http_query}"

270

print(f"Request URL: {url}")

271

272

# Parse path for Swift components

273

if e.http_path:

274

path_parts = e.http_path.strip('/').split('/')

275

if len(path_parts) >= 2:

276

print(f"Swift Account: {path_parts[1]}")

277

if len(path_parts) >= 3:

278

print(f"Container: {path_parts[2]}")

279

if len(path_parts) >= 4:

280

print(f"Object: {'/'.join(path_parts[3:])}")

281

282

# Response content analysis

283

if e.http_response_content:

284

content = e.http_response_content

285

if len(content) > 200:

286

content = content[:200] + "... (truncated)"

287

print(f"Response content: {content}")

288

289

# Common error patterns

290

if e.http_status == 422:

291

print("Unprocessable Entity - check request format and parameters")

292

elif e.http_status == 413:

293

print("Request Entity Too Large - object exceeds size limits")

294

elif e.http_status == 412:

295

print("Precondition Failed - check If-Match, If-None-Match headers")

296

elif e.http_status == 416:

297

print("Range Not Satisfiable - check Range header format")

298

299

# Usage

300

try:

301

conn.get_object('container', 'object')

302

except ClientException as e:

303

analyze_swift_error(e)

304

```

305

306

### Bulk Operation Error Handling

307

308

```python

309

from swiftclient.service import SwiftService, SwiftError

310

311

def handle_bulk_errors(results_generator, operation_name):

312

"""Handle errors from SwiftService bulk operations."""

313

314

success_count = 0

315

error_count = 0

316

317

for result in results_generator:

318

if result['success']:

319

success_count += 1

320

print(f"✓ {result.get('object', result.get('container', 'item'))}")

321

else:

322

error_count += 1

323

error = result['error']

324

item = result.get('object', result.get('container', 'unknown'))

325

326

print(f"✗ {item}: {error}")

327

328

# Handle specific SwiftError types

329

if isinstance(error, SwiftError):

330

if error.exception:

331

underlying = error.exception

332

if isinstance(underlying, ClientException):

333

if underlying.http_status == 404:

334

print(f" → Item not found, skipping")

335

elif underlying.http_status in (401, 403):

336

print(f" → Access denied, check permissions")

337

elif underlying.http_status >= 500:

338

print(f" → Server error, transaction: {underlying.transaction_id}")

339

340

# Container context

341

if error.container:

342

print(f" → Container: {error.container}")

343

344

# Object context

345

if error.obj:

346

print(f" → Object: {error.obj}")

347

348

# Segment context (for large objects)

349

if error.segment:

350

print(f" → Segment: {error.segment}")

351

352

print(f"\n{operation_name} Summary:")

353

print(f" Success: {success_count}")

354

print(f" Errors: {error_count}")

355

356

return success_count, error_count

357

358

# Usage

359

with SwiftService(options=auth_options) as swift:

360

# Handle upload errors

361

upload_objects = ['file1.txt', 'file2.txt', 'missing_file.txt']

362

results = swift.upload('container', upload_objects)

363

handle_bulk_errors(results, "Upload")

364

365

# Handle download errors

366

download_objects = ['existing.txt', 'missing.txt']

367

results = swift.download('container', download_objects)

368

handle_bulk_errors(results, "Download")

369

```

370

371

### Connection Error Recovery

372

373

```python

374

def create_resilient_connection(options, max_connection_attempts=3):

375

"""Create Swift connection with automatic retry on connection errors."""

376

377

for attempt in range(max_connection_attempts):

378

try:

379

conn = Connection(**options)

380

# Test connection

381

conn.head_account()

382

print("Connection established successfully")

383

return conn

384

385

except ClientException as e:

386

if e.http_status == 401:

387

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

388

if 'token' in options:

389

print("Token may be expired, removing from options")

390

options = options.copy()

391

del options['token']

392

continue

393

else:

394

raise # Credential error, don't retry

395

396

elif e.http_status is None:

397

# Network error

398

if attempt < max_connection_attempts - 1:

399

wait_time = 5 * (2 ** attempt)

400

print(f"Connection failed, retrying in {wait_time}s...")

401

time.sleep(wait_time)

402

continue

403

else:

404

raise

405

406

else:

407

# Other HTTP error

408

raise

409

410

except Exception as e:

411

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

412

if attempt < max_connection_attempts - 1:

413

time.sleep(2)

414

continue

415

else:

416

raise

417

418

raise RuntimeError("Failed to establish connection after all attempts")

419

420

# Usage

421

options = {

422

'authurl': 'https://identity.example.com:5000/v3',

423

'user': 'myuser',

424

'key': 'mypassword',

425

'auth_version': '3',

426

'os_options': {'project_name': 'myproject'}

427

}

428

429

conn = create_resilient_connection(options)

430

```