or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-support.mdcore-data-types.mddistance-calculations.mderror-handling.mdgeocoding-services.mdindex.mdrate-limiting.md

error-handling.mddocs/

0

# Error Handling

1

2

Geopy provides a comprehensive exception hierarchy covering authentication failures, quota exceeded, rate limiting, service unavailability, and parsing errors with detailed error information for robust error handling.

3

4

## Capabilities

5

6

### Base Exception

7

8

All geopy exceptions inherit from the base GeopyError class.

9

10

```python { .api }

11

from geopy.exc import GeopyError

12

13

class GeopyError(Exception):

14

"""

15

Base exception for all geopy-specific errors.

16

All other geopy exceptions inherit from this class.

17

"""

18

```

19

20

### Configuration Errors

21

22

Errors related to geocoder initialization and configuration.

23

24

```python { .api }

25

from geopy.exc import ConfigurationError

26

27

class ConfigurationError(GeopyError):

28

"""

29

Exception raised when geocoder is initialized with invalid parameters.

30

31

Common causes:

32

- Missing required API keys

33

- Invalid domain or scheme settings

34

- Conflicting authentication parameters

35

"""

36

```

37

38

### Service Errors

39

40

Errors returned by geocoding services during API requests.

41

42

```python { .api }

43

from geopy.exc import (

44

GeocoderServiceError, GeocoderQueryError, GeocoderQuotaExceeded,

45

GeocoderRateLimited, GeocoderAuthenticationFailure,

46

GeocoderInsufficientPrivileges, GeocoderTimedOut,

47

GeocoderUnavailable, GeocoderParseError

48

)

49

50

class GeocoderServiceError(GeopyError):

51

"""

52

Base class for all geocoding service errors.

53

Represents generic service-side issues.

54

"""

55

56

class GeocoderQueryError(GeocoderServiceError):

57

"""

58

Exception raised when geocoding service cannot process the query.

59

60

Common causes:

61

- Malformed query string

62

- Invalid coordinates for reverse geocoding

63

- Query contains unsupported characters

64

- Query exceeds maximum length limits

65

"""

66

67

class GeocoderQuotaExceeded(GeocoderServiceError):

68

"""

69

Exception raised when API quota or usage limits are exceeded.

70

71

Common causes:

72

- Daily/monthly request limit reached

73

- Rate limits exceeded

74

- Billing account suspended

75

"""

76

77

class GeocoderRateLimited(GeocoderServiceError):

78

"""

79

Exception raised when requests are being rate limited.

80

81

Attributes:

82

- retry_after (int): Seconds to wait before retrying (if provided by service)

83

"""

84

85

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

86

"""

87

Initialize rate limiting exception.

88

89

Parameters:

90

- message (str): Error message

91

- retry_after (int): Seconds to wait before retry

92

"""

93

super().__init__(message)

94

self.retry_after = retry_after

95

96

class GeocoderAuthenticationFailure(GeocoderServiceError):

97

"""

98

Exception raised when API authentication fails.

99

100

Common causes:

101

- Invalid API key

102

- Expired API key

103

- API key not authorized for service

104

- Missing authentication credentials

105

"""

106

107

class GeocoderInsufficientPrivileges(GeocoderServiceError):

108

"""

109

Exception raised when API key lacks required permissions.

110

111

Common causes:

112

- API key restricted to specific domains/IPs

113

- Service not enabled for API key

114

- Premium features require upgraded account

115

"""

116

117

class GeocoderTimedOut(GeocoderServiceError):

118

"""

119

Exception raised when geocoding request times out.

120

121

Common causes:

122

- Network connectivity issues

123

- Service experiencing high load

124

- Timeout value set too low

125

"""

126

127

class GeocoderUnavailable(GeocoderServiceError):

128

"""

129

Exception raised when geocoding service is unavailable.

130

131

Common causes:

132

- Service maintenance

133

- Server downtime

134

- Network infrastructure issues

135

"""

136

137

class GeocoderParseError(GeocoderServiceError):

138

"""

139

Exception raised when geocoder response cannot be parsed.

140

141

Common causes:

142

- Unexpected response format

143

- Malformed JSON/XML response

144

- Service API changes

145

"""

146

```

147

148

### Utility Errors

149

150

Errors related to geopy utilities and helper functions.

151

152

```python { .api }

153

from geopy.exc import GeocoderNotFound

154

155

class GeocoderNotFound(GeopyError):

156

"""

157

Exception raised when requesting unknown geocoder service.

158

159

Raised by get_geocoder_for_service() when service name

160

is not recognized.

161

"""

162

```

163

164

## Usage Examples

165

166

### Basic Error Handling

167

168

```python

169

from geopy.geocoders import Nominatim

170

from geopy.exc import (

171

GeopyError, GeocoderServiceError, GeocoderTimedOut,

172

GeocoderAuthenticationFailure, GeocoderQuotaExceeded

173

)

174

175

def safe_geocode(query, geolocator):

176

"""Safely geocode with comprehensive error handling"""

177

try:

178

location = geolocator.geocode(query, timeout=10)

179

return location

180

181

except GeocoderAuthenticationFailure as e:

182

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

183

print("Check your API key and permissions")

184

return None

185

186

except GeocoderQuotaExceeded as e:

187

print(f"Quota exceeded: {e}")

188

print("Consider upgrading your plan or waiting until quota resets")

189

return None

190

191

except GeocoderTimedOut as e:

192

print(f"Request timed out: {e}")

193

print("Try again with a longer timeout or check network connectivity")

194

return None

195

196

except GeocoderServiceError as e:

197

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

198

print("The geocoding service encountered an error")

199

return None

200

201

except GeopyError as e:

202

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

203

return None

204

205

except Exception as e:

206

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

207

return None

208

209

# Usage

210

geolocator = Nominatim(user_agent="my_app")

211

result = safe_geocode("New York City", geolocator)

212

if result:

213

print(f"Found: {result.address}")

214

else:

215

print("Geocoding failed")

216

```

217

218

### Rate Limiting Error Handling

219

220

```python

221

from geopy.geocoders import GoogleV3

222

from geopy.exc import GeocoderRateLimited, GeocoderQuotaExceeded

223

import time

224

225

def geocode_with_retry(query, geolocator, max_retries=3):

226

"""Geocode with automatic retry on rate limiting"""

227

228

for attempt in range(max_retries + 1):

229

try:

230

return geolocator.geocode(query)

231

232

except GeocoderRateLimited as e:

233

if attempt == max_retries:

234

raise # Re-raise on final attempt

235

236

# Wait before retry

237

wait_time = e.retry_after if e.retry_after else 2 ** attempt

238

print(f"Rate limited. Waiting {wait_time} seconds...")

239

time.sleep(wait_time)

240

241

except GeocoderQuotaExceeded:

242

print("Quota exceeded. Cannot retry.")

243

raise

244

245

return None

246

247

# Usage

248

try:

249

geolocator = GoogleV3(api_key="your_api_key")

250

location = geocode_with_retry("San Francisco", geolocator)

251

print(f"Result: {location.address if location else 'Not found'}")

252

253

except GeocoderRateLimited:

254

print("Still rate limited after retries")

255

except GeocoderQuotaExceeded:

256

print("API quota exceeded")

257

```

258

259

### Service Fallback Strategy

260

261

```python

262

from geopy.geocoders import Nominatim, Photon, OpenCage

263

from geopy.exc import (

264

GeopyError, GeocoderServiceError, GeocoderTimedOut,

265

GeocoderUnavailable, GeocoderAuthenticationFailure

266

)

267

268

class FallbackGeocoder:

269

"""Geocoder with automatic fallback to alternative services"""

270

271

def __init__(self):

272

self.geocoders = [

273

("Primary", Nominatim(user_agent="fallback_app")),

274

("Fallback1", Photon(user_agent="fallback_app")),

275

# Add more geocoders as needed

276

]

277

278

def geocode(self, query, exactly_one=True):

279

"""Try geocoding with fallback services"""

280

last_error = None

281

282

for name, geocoder in self.geocoders:

283

try:

284

print(f"Trying {name}...")

285

result = geocoder.geocode(query, exactly_one=exactly_one, timeout=10)

286

if result:

287

print(f"Success with {name}")

288

return result

289

else:

290

print(f"No results from {name}")

291

292

except (GeocoderUnavailable, GeocoderTimedOut) as e:

293

print(f"{name} unavailable: {e}")

294

last_error = e

295

continue

296

297

except GeocoderAuthenticationFailure as e:

298

print(f"{name} authentication failed: {e}")

299

last_error = e

300

continue

301

302

except GeocoderServiceError as e:

303

print(f"{name} service error: {e}")

304

last_error = e

305

continue

306

307

except GeopyError as e:

308

print(f"{name} geopy error: {e}")

309

last_error = e

310

continue

311

312

# All services failed

313

if last_error:

314

raise last_error

315

else:

316

return None

317

318

# Usage

319

fallback_geocoder = FallbackGeocoder()

320

try:

321

location = fallback_geocoder.geocode("Paris, France")

322

if location:

323

print(f"Found: {location.address}")

324

else:

325

print("No results from any service")

326

except Exception as e:

327

print(f"All services failed: {e}")

328

```

329

330

### Error Logging and Monitoring

331

332

```python

333

from geopy.geocoders import Bing

334

from geopy.exc import *

335

import logging

336

from datetime import datetime

337

from collections import defaultdict

338

339

# Configure logging

340

logging.basicConfig(level=logging.INFO)

341

logger = logging.getLogger(__name__)

342

343

class MonitoredGeocoder:

344

"""Geocoder wrapper with error monitoring and logging"""

345

346

def __init__(self, geocoder):

347

self.geocoder = geocoder

348

self.error_counts = defaultdict(int)

349

self.total_requests = 0

350

self.successful_requests = 0

351

352

def geocode(self, query, **kwargs):

353

"""Geocode with monitoring"""

354

self.total_requests += 1

355

start_time = datetime.now()

356

357

try:

358

result = self.geocoder.geocode(query, **kwargs)

359

360

if result:

361

self.successful_requests += 1

362

duration = (datetime.now() - start_time).total_seconds()

363

logger.info(f"Geocoding success: '{query}' -> {result.address} ({duration:.2f}s)")

364

else:

365

logger.warning(f"Geocoding returned no results: '{query}'")

366

367

return result

368

369

except GeocoderAuthenticationFailure as e:

370

self.error_counts['auth_failure'] += 1

371

logger.error(f"Authentication failure for '{query}': {e}")

372

raise

373

374

except GeocoderQuotaExceeded as e:

375

self.error_counts['quota_exceeded'] += 1

376

logger.error(f"Quota exceeded for '{query}': {e}")

377

raise

378

379

except GeocoderRateLimited as e:

380

self.error_counts['rate_limited'] += 1

381

logger.warning(f"Rate limited for '{query}': {e} (retry_after={e.retry_after})")

382

raise

383

384

except GeocoderTimedOut as e:

385

self.error_counts['timeout'] += 1

386

logger.warning(f"Timeout for '{query}': {e}")

387

raise

388

389

except GeocoderUnavailable as e:

390

self.error_counts['unavailable'] += 1

391

logger.error(f"Service unavailable for '{query}': {e}")

392

raise

393

394

except GeocoderServiceError as e:

395

self.error_counts['service_error'] += 1

396

logger.error(f"Service error for '{query}': {e}")

397

raise

398

399

except GeopyError as e:

400

self.error_counts['geopy_error'] += 1

401

logger.error(f"Geopy error for '{query}': {e}")

402

raise

403

404

def get_stats(self):

405

"""Get monitoring statistics"""

406

success_rate = (self.successful_requests / self.total_requests * 100

407

if self.total_requests > 0 else 0)

408

409

return {

410

'total_requests': self.total_requests,

411

'successful_requests': self.successful_requests,

412

'success_rate': success_rate,

413

'error_counts': dict(self.error_counts)

414

}

415

416

def print_stats(self):

417

"""Print monitoring statistics"""

418

stats = self.get_stats()

419

print(f"\nGeocoding Statistics:")

420

print(f"Total requests: {stats['total_requests']}")

421

print(f"Successful requests: {stats['successful_requests']}")

422

print(f"Success rate: {stats['success_rate']:.2f}%")

423

print(f"Error breakdown:")

424

for error_type, count in stats['error_counts'].items():

425

print(f" {error_type}: {count}")

426

427

# Usage

428

base_geocoder = Bing(api_key="your_api_key")

429

monitored_geocoder = MonitoredGeocoder(base_geocoder)

430

431

# Test queries

432

test_queries = [

433

"New York City",

434

"Invalid address 123456",

435

"London, UK",

436

"Tokyo, Japan"

437

]

438

439

for query in test_queries:

440

try:

441

result = monitored_geocoder.geocode(query)

442

except Exception as e:

443

print(f"Error processing '{query}': {e}")

444

445

# Print statistics

446

monitored_geocoder.print_stats()

447

```

448

449

### Custom Error Handling Context Manager

450

451

```python

452

from geopy.exc import *

453

from contextlib import contextmanager

454

import time

455

456

@contextmanager

457

def geocoding_context(max_retries=3, retry_delay=1):

458

"""Context manager for geocoding with automatic error handling"""

459

460

retry_count = 0

461

while retry_count <= max_retries:

462

try:

463

yield

464

break # Success, exit retry loop

465

466

except GeocoderRateLimited as e:

467

if retry_count == max_retries:

468

print(f"Rate limited after {max_retries} retries")

469

raise

470

471

wait_time = e.retry_after if e.retry_after else retry_delay * (2 ** retry_count)

472

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

473

time.sleep(wait_time)

474

retry_count += 1

475

476

except (GeocoderTimedOut, GeocoderUnavailable) as e:

477

if retry_count == max_retries:

478

print(f"Service issue after {max_retries} retries: {e}")

479

raise

480

481

print(f"Service issue, retrying in {retry_delay} seconds...")

482

time.sleep(retry_delay)

483

retry_count += 1

484

485

except (GeocoderAuthenticationFailure, GeocoderQuotaExceeded) as e:

486

print(f"Non-retryable error: {e}")

487

raise

488

489

except Exception as e:

490

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

491

raise

492

493

# Usage

494

from geopy.geocoders import Nominatim

495

496

geolocator = Nominatim(user_agent="context_app")

497

498

with geocoding_context(max_retries=3, retry_delay=2):

499

location = geolocator.geocode("San Francisco, CA")

500

print(f"Result: {location.address if location else 'Not found'}")

501

```