or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth.mdchannel.mddiscovery.mderrors.mdhttp.mdindex.mdmedia.mdmimeparse.mdmodel.mdschema.mdtesting.md

errors.mddocs/

0

# Error Handling and Exceptions

1

2

The Google API Python Client provides a comprehensive error handling system with structured exceptions that contain detailed information about failures, enabling robust error recovery and debugging.

3

4

## Capabilities

5

6

### Base Exception Classes

7

8

Foundation exception classes that provide common error handling functionality.

9

10

```python { .api }

11

class Error(Exception):

12

"""Base exception class for all Google API client errors."""

13

pass

14

```

15

16

### HTTP Error Classes

17

18

Exceptions related to HTTP request failures with detailed response information.

19

20

```python { .api }

21

class HttpError(Error):

22

"""HTTP request failed with an error response from the server."""

23

24

def __init__(self, resp, content, uri=None):

25

"""

26

Initialize an HTTP error.

27

28

Args:

29

resp (httplib2.Response): HTTP response object

30

content (bytes): Response body content

31

uri (str, optional): URI that was requested

32

"""

33

34

@property

35

def resp(self):

36

"""

37

Get the HTTP response object.

38

39

Returns:

40

httplib2.Response: The HTTP response with status, headers, etc.

41

"""

42

43

@property

44

def content(self):

45

"""

46

Get the response body content.

47

48

Returns:

49

bytes: Raw response content

50

"""

51

52

@property

53

def error_details(self):

54

"""

55

Get structured error details from the response.

56

57

Returns:

58

list: List of error detail dictionaries, or empty list if none

59

"""

60

61

@property

62

def status_code(self):

63

"""

64

Get the HTTP status code.

65

66

Returns:

67

int: HTTP status code (e.g., 404, 500)

68

"""

69

70

def _get_reason(self):

71

"""

72

Extract the error reason from the response.

73

74

Returns:

75

str: Human-readable error reason

76

"""

77

78

class MediaUploadSizeError(HttpError):

79

"""Media upload size exceeds the allowed limits."""

80

pass

81

82

class BatchError(HttpError):

83

"""Error occurred during batch request processing."""

84

85

def __init__(self, reason, resp=None, content=None):

86

"""

87

Initialize a batch error.

88

89

Args:

90

reason (str): Description of the batch error

91

resp (httplib2.Response, optional): HTTP response object

92

content (bytes, optional): Response content

93

"""

94

95

class ResumableUploadError(HttpError):

96

"""Error occurred during resumable upload processing."""

97

pass

98

```

99

100

### API-Specific Error Classes

101

102

Exceptions for specific API operation failures.

103

104

```python { .api }

105

class InvalidJsonError(Error):

106

"""Response contained invalid JSON that could not be parsed."""

107

pass

108

109

class UnknownFileType(Error):

110

"""Media upload failed due to unknown or unsupported file type."""

111

pass

112

113

class UnknownLinkType(Error):

114

"""Link type unknown or unexpected."""

115

116

def __init__(self):

117

"""Initialize an unknown link type error."""

118

119

class UnacceptableMimeTypeError(Error):

120

"""That is an unacceptable mimetype for this operation."""

121

122

def __init__(self):

123

"""Initialize an unacceptable MIME type error."""

124

125

class InvalidChunkSizeError(Error):

126

"""The given chunksize is not valid."""

127

128

def __init__(self):

129

"""Initialize an invalid chunk size error."""

130

131

class InvalidNotificationError(Error):

132

"""The channel Notification is invalid."""

133

134

def __init__(self):

135

"""Initialize an invalid notification error."""

136

137

class UnknownApiNameOrVersion(Error):

138

"""No API with that name and version exists."""

139

140

def __init__(self):

141

"""Initialize an unknown API name or version error."""

142

143

class UnexpectedMethodError(Error):

144

"""Exception raised by RequestMockBuilder on unexpected calls."""

145

146

def __init__(self, methodId=None):

147

"""

148

Initialize an unexpected method error.

149

150

Args:

151

methodId (str, optional): Method identifier that was unexpected

152

"""

153

154

class UnexpectedBodyError(Error):

155

"""Exception raised by RequestMockBuilder on unexpected bodies."""

156

157

def __init__(self, expected, provided):

158

"""

159

Initialize an unexpected body error.

160

161

Args:

162

expected: Expected body content

163

provided: Provided body content

164

"""

165

```

166

167

## Usage Examples

168

169

### Basic Error Handling

170

171

```python

172

from googleapiclient import discovery

173

from googleapiclient.errors import HttpError

174

175

service = discovery.build('gmail', 'v1', credentials=credentials)

176

177

try:

178

# Attempt to get a message that might not exist

179

message = service.users().messages().get(

180

userId='me',

181

id='nonexistent_message_id'

182

).execute()

183

except HttpError as error:

184

print(f'HTTP Error {error.status_code}: {error._get_reason()}')

185

print(f'Response content: {error.content}')

186

```

187

188

### Detailed Error Information

189

190

```python

191

from googleapiclient.errors import HttpError

192

import json

193

194

try:

195

response = service.users().messages().list(userId='invalid_user').execute()

196

except HttpError as error:

197

print(f'Status Code: {error.status_code}')

198

print(f'Reason: {error._get_reason()}')

199

200

# Parse error details from response content

201

try:

202

error_content = json.loads(error.content.decode('utf-8'))

203

if 'error' in error_content:

204

error_info = error_content['error']

205

print(f'Error Code: {error_info.get("code")}')

206

print(f'Error Message: {error_info.get("message")}')

207

208

# Check for detailed error information

209

if 'errors' in error_info:

210

for detail in error_info['errors']:

211

print(f' - {detail.get("reason")}: {detail.get("message")}')

212

except (json.JSONDecodeError, UnicodeDecodeError):

213

print(f'Raw error content: {error.content}')

214

```

215

216

### Error-Specific Handling

217

218

```python

219

from googleapiclient.errors import (

220

HttpError, BatchError, MediaUploadSizeError,

221

UnknownApiNameOrVersion, InvalidJsonError

222

)

223

224

try:

225

# Various operations that might fail

226

service = discovery.build('unknown-api', 'v1', credentials=credentials)

227

228

except UnknownApiNameOrVersion as error:

229

print(f'API not available: {error}')

230

# Fallback to a different API or version

231

232

except HttpError as error:

233

if error.status_code == 401:

234

print('Authentication failed - check credentials')

235

elif error.status_code == 403:

236

print('Access forbidden - check permissions/quotas')

237

elif error.status_code == 404:

238

print('Resource not found')

239

elif error.status_code == 429:

240

print('Rate limit exceeded - implement backoff')

241

elif error.status_code >= 500:

242

print('Server error - retry may help')

243

else:

244

print(f'HTTP error {error.status_code}: {error._get_reason()}')

245

246

except BatchError as error:

247

print(f'Batch processing failed: {error}')

248

249

except MediaUploadSizeError as error:

250

print(f'File too large for upload: {error}')

251

252

except InvalidJsonError as error:

253

print(f'Invalid JSON in response: {error}')

254

```

255

256

### Retry Logic with Error Handling

257

258

```python

259

from googleapiclient.errors import HttpError

260

import time

261

import random

262

263

def execute_with_retry(request, max_retries=3, backoff_factor=1.5):

264

"""

265

Execute a request with exponential backoff retry logic.

266

267

Args:

268

request: The HttpRequest to execute

269

max_retries (int): Maximum number of retry attempts

270

backoff_factor (float): Multiplier for exponential backoff

271

272

Returns:

273

Response object from successful request

274

275

Raises:

276

HttpError: When all retry attempts are exhausted

277

"""

278

last_error = None

279

280

for attempt in range(max_retries + 1):

281

try:

282

return request.execute()

283

284

except HttpError as error:

285

last_error = error

286

287

# Don't retry on client errors (4xx) except for specific cases

288

if 400 <= error.status_code < 500:

289

if error.status_code not in [429, 408]: # Rate limit, timeout

290

raise

291

292

# Don't retry on the last attempt

293

if attempt == max_retries:

294

raise

295

296

# Calculate wait time with jitter

297

wait_time = (backoff_factor ** attempt) + random.uniform(0, 1)

298

print(f'Request failed (attempt {attempt + 1}), retrying in {wait_time:.1f}s...')

299

time.sleep(wait_time)

300

301

# This should never be reached, but just in case

302

raise last_error

303

304

# Usage

305

try:

306

request = service.users().messages().list(userId='me')

307

response = execute_with_retry(request, max_retries=3)

308

print(f'Success: {len(response.get("messages", []))} messages')

309

except HttpError as error:

310

print(f'Request failed after retries: {error._get_reason()}')

311

```

312

313

### Batch Error Handling

314

315

```python

316

from googleapiclient import http

317

from googleapiclient.errors import HttpError, BatchError

318

319

def batch_callback(request_id, response, exception):

320

"""Handle individual batch request results with error processing."""

321

if exception is not None:

322

if isinstance(exception, HttpError):

323

print(f'Request {request_id} failed with HTTP {exception.status_code}')

324

print(f' Reason: {exception._get_reason()}')

325

326

# Handle specific error codes

327

if exception.status_code == 404:

328

print(f' Resource not found for request {request_id}')

329

elif exception.status_code == 403:

330

print(f' Access denied for request {request_id}')

331

else:

332

print(f'Request {request_id} failed: {exception}')

333

else:

334

print(f'Request {request_id} succeeded')

335

336

try:

337

batch = http.BatchHttpRequest(callback=batch_callback)

338

339

# Add requests that might fail

340

batch.add(service.users().messages().get(userId='me', id='valid_id'),

341

request_id='valid_message')

342

batch.add(service.users().messages().get(userId='me', id='invalid_id'),

343

request_id='invalid_message')

344

345

batch.execute()

346

347

except BatchError as error:

348

print(f'Batch execution failed: {error}')

349

except HttpError as error:

350

print(f'Batch request failed: {error._get_reason()}')

351

```

352

353

### Custom Error Handler

354

355

```python

356

from googleapiclient.errors import HttpError

357

import logging

358

359

class ApiErrorHandler:

360

"""Custom error handler for Google API operations."""

361

362

def __init__(self, logger=None):

363

self.logger = logger or logging.getLogger(__name__)

364

365

def handle_error(self, error, operation_name, **context):

366

"""

367

Handle API errors with logging and context.

368

369

Args:

370

error (Exception): The error that occurred

371

operation_name (str): Name of the operation that failed

372

**context: Additional context information

373

"""

374

if isinstance(error, HttpError):

375

self.logger.error(

376

f'{operation_name} failed: HTTP {error.status_code} - {error._get_reason()}',

377

extra={

378

'status_code': error.status_code,

379

'operation': operation_name,

380

'context': context

381

}

382

)

383

384

# Return suggested action

385

if error.status_code == 401:

386

return 'refresh_credentials'

387

elif error.status_code == 403:

388

return 'check_permissions'

389

elif error.status_code == 429:

390

return 'implement_backoff'

391

elif error.status_code >= 500:

392

return 'retry_request'

393

else:

394

return 'check_request_parameters'

395

else:

396

self.logger.error(f'{operation_name} failed: {error}', extra={

397

'operation': operation_name,

398

'context': context

399

})

400

return 'unknown_error'

401

402

# Usage

403

error_handler = ApiErrorHandler()

404

405

try:

406

messages = service.users().messages().list(userId='me').execute()

407

except Exception as error:

408

action = error_handler.handle_error(

409

error,

410

'list_messages',

411

user_id='me',

412

service='gmail'

413

)

414

415

if action == 'refresh_credentials':

416

# Implement credential refresh logic

417

pass

418

elif action == 'implement_backoff':

419

# Implement rate limiting backoff

420

pass

421

```

422

423

### Error Details Extraction

424

425

```python

426

from googleapiclient.errors import HttpError

427

import json

428

429

def extract_error_details(error):

430

"""

431

Extract detailed error information from HttpError.

432

433

Args:

434

error (HttpError): The HTTP error to analyze

435

436

Returns:

437

dict: Structured error information

438

"""

439

details = {

440

'status_code': error.status_code,

441

'reason': error._get_reason(),

442

'errors': []

443

}

444

445

try:

446

# Parse JSON error response

447

content = json.loads(error.content.decode('utf-8'))

448

449

if 'error' in content:

450

error_info = content['error']

451

details['code'] = error_info.get('code')

452

details['message'] = error_info.get('message')

453

454

# Extract individual error details

455

if 'errors' in error_info:

456

for err in error_info['errors']:

457

details['errors'].append({

458

'domain': err.get('domain'),

459

'reason': err.get('reason'),

460

'message': err.get('message'),

461

'location': err.get('location'),

462

'location_type': err.get('locationType')

463

})

464

465

except (json.JSONDecodeError, UnicodeDecodeError, KeyError):

466

# Fallback to raw content

467

details['raw_content'] = error.content.decode('utf-8', errors='ignore')

468

469

return details

470

471

# Usage

472

try:

473

response = service.users().messages().get(userId='me', id='bad_id').execute()

474

except HttpError as error:

475

error_details = extract_error_details(error)

476

print(f'Error: {error_details["message"]}')

477

478

for err in error_details['errors']:

479

print(f' - {err["reason"]}: {err["message"]}')

480

if err['location']:

481

print(f' Location: {err["location"]} ({err["location_type"]})')

482

```