Error Handling

Proper error handling is crucial for building robust applications with Gspace.

Common Error Types

Authentication Errors

python
from google.auth.exceptions import RefreshError

try:
    gspace = GSpace.from_oauth(credentials_file, scopes)
except RefreshError as e:
    print("Authentication failed. Please re-authenticate.")
except FileNotFoundError:
    print("Credentials file not found.")

HTTP Errors

python
from googleapiclient.errors import HttpError

try:
    event = calendar.create_event(...)
except HttpError as e:
    if e.resp.status == 404:
        print("Resource not found")
    elif e.resp.status == 403:
        print("Permission denied")
    elif e.resp.status == 429:
        print("Rate limit exceeded")
    else:
        print(f"HTTP Error {e.resp.status}: {e}")

Validation Errors

python
try:
    calendar.create_event(
        summary="Meeting",
        start_time=datetime.now(),
        end_time=datetime.now() - timedelta(hours=1)  # Invalid!
    )
except ValueError as e:
    print(f"Validation error: {e}")

Error Handling Patterns

Retry Pattern

python
from functools import wraps
import time

def retry_on_failure(max_retries=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except HttpError as e:
                    if attempt < max_retries - 1:
                        if e.resp.status in [429, 500, 503]:
                            time.sleep(delay * (2 ** attempt))
                            continue
                    raise
            return None
        return wrapper
    return decorator

@retry_on_failure(max_retries=3)
def create_event_safe(*args, **kwargs):
    return calendar.create_event(*args, **kwargs)

Error Logging

python
import logging
from gspace.utils.logger import get_logger

logger = get_logger("gspace.app")

try:
    event = calendar.create_event(...)
except Exception as e:
    logger.error(f"Failed to create event: {e}", exc_info=True)
    # Handle error appropriately

Graceful Degradation

python
def get_calendar_events_safe(calendar_id="primary"):
    try:
        return calendar.list_events(calendar_id=calendar_id)
    except HttpError as e:
        if e.resp.status == 403:
            logger.warning("No access to calendar, returning empty list")
            return []
        elif e.resp.status == 404:
            logger.warning("Calendar not found")
            return []
        else:
            raise

Error Categories

Recoverable Errors

These errors can be retried:

  • 429 Too Many Requests - Rate limiting
  • 500 Internal Server Error - Server-side errors
  • 503 Service Unavailable - Temporary unavailability

Non-Recoverable Errors

These require user action:

  • 401 Unauthorized - Authentication required
  • 403 Forbidden - Permission denied
  • 404 Not Found - Resource doesn't exist
  • 400 Bad Request - Invalid request parameters

Best Practices

  1. Always wrap API calls - Use try-except blocks
  2. Log errors appropriately - Use appropriate log levels
  3. Provide user feedback - Inform users of errors
  4. Implement retries - For transient errors
  5. Validate input - Catch errors early
  6. Handle specific errors - Different errors need different handling

Error Handling Utilities

Custom Exception Classes

python
class GSpaceError(Exception):
    """Base exception for Gspace errors"""
    pass

class AuthenticationError(GSpaceError):
    """Authentication related errors"""
    pass

class QuotaExceededError(GSpaceError):
    """Quota limit exceeded"""
    pass

class PermissionError(GSpaceError):
    """Permission denied errors"""
    pass

Error Handler Context Manager

python
from contextlib import contextmanager

@contextmanager
def handle_api_errors():
    try:
        yield
    except HttpError as e:
        if e.resp.status == 429:
            raise QuotaExceededError() from e
        elif e.resp.status == 403:
            raise PermissionError() from e
        else:
            raise GSpaceError(f"API error: {e}") from e

# Usage
with handle_api_errors():
    calendar.create_event(...)

Testing Error Scenarios

python
import pytest
from unittest.mock import patch

def test_rate_limit_handling():
    with patch('calendar.service') as mock_service:
        mock_service.side_effect = HttpError(
            resp=type('obj', (object,), {'status': 429})(),
            content=b'Rate limit exceeded'
        )
        
        with pytest.raises(QuotaExceededError):
            calendar.create_event(...)