CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-geoip2

MaxMind GeoIP2 API for IP geolocation using web services and databases

Pending
Overview
Eval results
Files

errors.mddocs/

Error Handling

Comprehensive exception hierarchy for handling various error conditions that can occur during web service requests and database lookups. The exceptions provide detailed information about failures including network errors, authentication problems, and data availability issues.

import ipaddress
from typing import Optional, Union

Capabilities

Base Exception

The root exception class for all GeoIP2-specific errors.

class GeoIP2Error(RuntimeError):
    """
    Base exception for all GeoIP2 errors.
    
    This class represents a generic error and extends RuntimeError
    without adding additional attributes.
    """

Address Lookup Errors

Exceptions related to IP address lookup failures.

class AddressNotFoundError(GeoIP2Error):
    """
    The IP address was not found in the database or web service.
    
    For database lookups, this provides the network information
    for efficient subnet enumeration.
    """
    
    def __init__(self, message: str, ip_address: Optional[str] = None, 
                 prefix_len: Optional[int] = None): ...
    
    ip_address: Optional[str]                   # IP address used in lookup (database only)
    
    @property
    def network(self) -> Optional[Union[ipaddress.IPv4Network, ipaddress.IPv6Network]]:
        """
        The network associated with the error.
        
        For database lookups, this is the largest network where no address
        would be found. Useful for efficient subnet enumeration.
        
        Returns:
        Network object or None if not available
        """

Authentication and Authorization Errors

Exceptions for credential and permission issues with web services.

class AuthenticationError(GeoIP2Error):
    """
    Authentication failed due to invalid credentials.
    
    This occurs when the account ID or license key is invalid,
    missing, or unauthorized for the requested service.
    """

class PermissionRequiredError(GeoIP2Error):
    """
    The account does not have permission to access the requested service.
    
    This typically occurs when trying to access Insights endpoint
    without an Insights subscription.
    """

class OutOfQueriesError(GeoIP2Error):
    """
    The account has exceeded its query limit or is out of funds.
    
    Check your MaxMind account for remaining queries or billing status.
    """

Network and Request Errors

Exceptions for HTTP transport and network communication issues.

class HTTPError(GeoIP2Error):
    """
    An HTTP transport error occurred during the web service request.
    
    This represents network-level failures, server errors, or
    unexpected HTTP responses.
    """
    
    def __init__(self, message: str, http_status: Optional[int] = None, 
                 uri: Optional[str] = None, decoded_content: Optional[str] = None): ...
    
    http_status: Optional[int]                  # HTTP status code returned
    uri: Optional[str]                          # URI that was queried
    decoded_content: Optional[str]              # Response body content

class InvalidRequestError(GeoIP2Error):
    """
    The request was invalid or malformed.
    
    This can occur with invalid IP addresses, unsupported parameters,
    or other client-side request errors.
    """

Usage Examples

Basic Error Handling

import geoip2.webservice
from geoip2.errors import (
    AddressNotFoundError, 
    AuthenticationError, 
    OutOfQueriesError,
    HTTPError
)

try:
    with geoip2.webservice.Client(42, 'license_key') as client:
        response = client.city('127.0.0.1')  # Private IP
        print(response.country.name)
        
except AddressNotFoundError:
    print("IP address not found in database")
    
except AuthenticationError:
    print("Invalid account ID or license key")
    
except OutOfQueriesError:
    print("Account is out of queries")
    
except HTTPError as e:
    print(f"HTTP error {e.http_status}: {e.decoded_content}")
    
except GeoIP2Error as e:
    print(f"Other GeoIP2 error: {e}")

Database Error Handling with Network Information

import geoip2.database
from geoip2.errors import AddressNotFoundError

try:
    with geoip2.database.Reader('/path/to/GeoLite2-City.mmdb') as reader:
        response = reader.city('10.0.0.1')  # Private IP
        
except AddressNotFoundError as e:
    print(f"Address {e.ip_address} not found")
    if e.network:
        print(f"No data available for entire network: {e.network}")
        
except FileNotFoundError:
    print("Database file not found")
    
except PermissionError:
    print("Permission denied accessing database file")

Comprehensive Web Service Error Handling

import geoip2.webservice
from geoip2.errors import (
    AddressNotFoundError,
    AuthenticationError, 
    PermissionRequiredError,
    OutOfQueriesError,
    InvalidRequestError,
    HTTPError,
    GeoIP2Error
)

def lookup_ip_with_error_handling(ip_address):
    try:
        with geoip2.webservice.Client(42, 'license_key') as client:
            # Try Insights first (most comprehensive data)
            try:
                return client.insights(ip_address)
            except PermissionRequiredError:
                # Fall back to City if no Insights permission
                return client.city(ip_address)
                
    except AddressNotFoundError:
        print(f"IP {ip_address} not found in database")
        return None
        
    except AuthenticationError:
        print("Authentication failed - check account ID and license key")
        return None
        
    except OutOfQueriesError:
        print("Account out of queries - check billing status")
        return None
        
    except InvalidRequestError as e:
        print(f"Invalid request: {e}")
        return None
        
    except HTTPError as e:
        if e.http_status == 500:
            print("Server error - try again later")
        elif e.http_status == 503:
            print("Service unavailable - try again later")
        else:
            print(f"HTTP error {e.http_status}: {e.decoded_content}")
        return None
        
    except GeoIP2Error as e:
        print(f"Unexpected GeoIP2 error: {e}")
        return None

Efficient Subnet Enumeration Using Error Networks

import geoip2.database
import geoip2.errors
import ipaddress

def enumerate_subnet_with_error_handling(database_path, subnet):
    """
    Efficiently enumerate a subnet using AddressNotFoundError.network
    to skip entire ranges with no data.
    """
    try:
        with geoip2.database.Reader(database_path) as reader:
            network = ipaddress.ip_network(subnet)
            ip_address = network[0]
            
            while ip_address in network:
                try:
                    response = reader.asn(ip_address)
                    response_network = response.network
                    print(f"{response_network}: ASN {response.autonomous_system_number}")
                    
                except geoip2.errors.AddressNotFoundError as e:
                    response_network = e.network
                    if response_network:
                        print(f"{response_network}: No data")
                    else:
                        # Single IP with no data
                        response_network = ipaddress.ip_network(f"{ip_address}/32", strict=False)
                        print(f"{ip_address}: No data")
                
                # Move to next subnet
                ip_address = response_network[-1] + 1
                
    except FileNotFoundError:
        print(f"Database file not found: {database_path}")
    except PermissionError:
        print(f"Permission denied: {database_path}")
    except Exception as e:
        print(f"Unexpected error: {e}")

Retry Logic for Transient Errors

import time
import geoip2.webservice
from geoip2.errors import HTTPError, GeoIP2Error

def lookup_with_retry(ip_address, max_retries=3, retry_delay=1.0):
    """
    Lookup IP with retry logic for transient errors.
    """
    for attempt in range(max_retries):
        try:
            with geoip2.webservice.Client(42, 'license_key') as client:
                return client.city(ip_address)
                
        except HTTPError as e:
            # Retry on server errors (5xx) and rate limiting (429)
            if e.http_status and (e.http_status >= 500 or e.http_status == 429):
                if attempt < max_retries - 1:
                    print(f"Server error {e.http_status}, retrying in {retry_delay}s...")
                    time.sleep(retry_delay)
                    retry_delay *= 2  # Exponential backoff
                    continue
            raise
            
        except GeoIP2Error:
            # Don't retry on client errors
            raise
            
    # If we get here, all retries failed
    raise HTTPError("Max retries exceeded")

Logging Error Details

import logging
import geoip2.webservice
from geoip2.errors import GeoIP2Error, HTTPError

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def lookup_with_logging(ip_address):
    try:
        with geoip2.webservice.Client(42, 'license_key') as client:
            response = client.city(ip_address)
            logger.info(f"Successfully looked up {ip_address}: {response.country.name}")
            return response
            
    except HTTPError as e:
        logger.error(f"HTTP error for {ip_address}: {e.http_status} {e.uri}")
        logger.debug(f"Response content: {e.decoded_content}")
        raise
        
    except GeoIP2Error as e:
        logger.error(f"GeoIP2 error for {ip_address}: {type(e).__name__}: {e}")
        raise
        
    except Exception as e:
        logger.error(f"Unexpected error for {ip_address}: {type(e).__name__}: {e}")
        raise

Common Error Scenarios

Web Service Errors

  • AddressNotFoundError: Private IPs (10.x.x.x, 192.168.x.x, 127.x.x.x), invalid IPs
  • AuthenticationError: Wrong account ID, expired license key, missing credentials
  • OutOfQueriesError: Monthly query limit exceeded, payment failure
  • PermissionRequiredError: Accessing Insights without subscription
  • HTTPError 429: Rate limiting (too many requests)
  • HTTPError 5xx: Server-side errors, maintenance windows

Database Errors

  • AddressNotFoundError: IP not in database coverage, private IP ranges
  • FileNotFoundError: Database file path incorrect or file deleted
  • PermissionError: Insufficient file system permissions
  • maxminddb.InvalidDatabaseError: Corrupted database file
  • TypeError: Wrong database type for lookup method (e.g., calling city() on ASN database)

Network Errors

  • HTTPError: DNS resolution failure, network connectivity issues
  • Timeout errors: Network timeout, slow server response
  • SSL errors: Certificate validation failure, TLS handshake errors

Install with Tessl CLI

npx tessl i tessl/pypi-geoip2

docs

database-reader.md

errors.md

index.md

models.md

web-service.md

tile.json