Error Handling Reference

This section documents all the exception classes and error handling patterns in the Upstox TOTP SDK.

Exception Hierarchy

BaseException
└── Exception
    └── UpstoxError (base for all SDK errors)
        ├── ConfigurationError
        ├── ValidationError
        ├── AuthenticationError
        ├── NetworkError
        └── APIError

Core Exceptions

UpstoxError

class upstox_totp.errors.UpstoxError(error_code, message, details=None)[source]

Bases: Exception

Base class for all Upstox API errors.

Initialize error with code, message and optional details.

Parameters:
  • error_code (ErrorCode)

  • message (str)

  • details (dict[str, Any] | None)

__init__(error_code, message, details=None)[source]

Initialize error with code, message and optional details.

Parameters:
  • error_code (ErrorCode)

  • message (str)

  • details (dict[str, Any] | None)

classmethod from_response(data)[source]

Create error from API response data.

Handles both old format and new format error responses.

Parameters:

data (dict[str, Any])

Return type:

UpstoxError

Base exception class for all Upstox TOTP SDK errors.

Attributes:

  • message (str): Human-readable error message

  • details (dict, optional): Additional error details

  • suggestions (list, optional): Troubleshooting suggestions

Example:

from upstox_totp import UpstoxTOTP, UpstoxError

try:
    upx = UpstoxTOTP()
    response = upx.app_token.get_access_token()
except UpstoxError as e:
    print(f"Error: {e}")
    print(f"Details: {e.details}")
    print(f"Suggestions: {e.suggestions}")

ConfigurationError

class upstox_totp.errors.ConfigurationError[source]

Bases: Exception

Raised when client configuration is invalid.

Raised when there are issues with configuration setup.

Common Causes:

  • Missing environment variables

  • Invalid credential format

  • Malformed configuration values

  • File permission issues

Example:

from upstox_totp import UpstoxTOTP, ConfigurationError

try:
    # Missing required environment variables
    upx = UpstoxTOTP()
except ConfigurationError as e:
    print(f"Configuration error: {e}")

    # Check what's missing
    if "UPSTOX_USERNAME" in str(e):
        print("Please set UPSTOX_USERNAME environment variable")

ValidationError

class upstox_totp.errors.ValidationError[source]

Bases: Exception

Raised when input validation fails.

Raised when input validation fails.

Common Causes:

  • Invalid username format (not 10 digits)

  • Invalid PIN code format

  • Invalid TOTP secret format

  • Invalid URL format for redirect_uri

Example:

from upstox_totp import UpstoxTOTP, ValidationError
from pydantic import SecretStr

try:
    upx = UpstoxTOTP(
        username="invalid",  # Should be 10 digits
        password=SecretStr("password"),
        # ... other fields
    )
except ValidationError as e:
    print(f"Validation error: {e}")

Error Handling Patterns

Basic Error Handling

from upstox_totp import UpstoxTOTP, UpstoxError

def safe_get_token():
    try:
        upx = UpstoxTOTP()
        response = upx.app_token.get_access_token()

        if response.success:
            return response.data.access_token
        else:
            print(f"API returned error: {response.error}")
            return None

    except UpstoxError as e:
        print(f"SDK error: {e}")
        return None
    except Exception as e:
        print(f"Unexpected error: {e}")
        return None

token = safe_get_token()
if token:
    print("Token generated successfully")

Specific Error Handling

from upstox_totp import (
    UpstoxTOTP,
    ConfigurationError,
    ValidationError,
    UpstoxError
)

def handle_specific_errors():
    try:
        upx = UpstoxTOTP()
        response = upx.app_token.get_access_token()
        return response

    except ConfigurationError as e:
        print("Configuration Issue:")
        print(f"  Error: {e}")
        print("  Solutions:")
        print("  - Check your .env file")
        print("  - Verify environment variables")
        print("  - Run: upstox_cli check-env")

    except ValidationError as e:
        print("Validation Issue:")
        print(f"  Error: {e}")
        print("  Solutions:")
        print("  - Check credential formats")
        print("  - Verify TOTP secret")
        print("  - Ensure username is 10 digits")

    except UpstoxError as e:
        print("Upstox API Issue:")
        print(f"  Error: {e}")
        if e.suggestions:
            print("  Suggestions:")
            for suggestion in e.suggestions:
                print(f"  - {suggestion}")

Retry Logic with Error Handling

import time
from upstox_totp import UpstoxTOTP, UpstoxError

def get_token_with_retry(max_retries=3, delay=5):
    """Get token with retry logic for different error types."""

    for attempt in range(1, max_retries + 1):
        try:
            upx = UpstoxTOTP()
            response = upx.app_token.get_access_token()

            if response.success:
                return response.data.access_token
            else:
                error = response.error
                print(f"Attempt {attempt}: API error - {error}")

                # Don't retry for certain errors
                if error and "invalid_credentials" in str(error):
                    print("Invalid credentials - not retrying")
                    break

        except ConfigurationError:
            print("Configuration error - not retrying")
            break  # Don't retry configuration errors

        except ValidationError:
            print("Validation error - not retrying")
            break  # Don't retry validation errors

        except UpstoxError as e:
            print(f"Attempt {attempt}: Upstox error - {e}")
            # Retry for network/temporary errors

        except Exception as e:
            print(f"Attempt {attempt}: Unexpected error - {e}")

        if attempt < max_retries:
            print(f"Retrying in {delay} seconds...")
            time.sleep(delay)

    raise Exception(f"Failed to get token after {max_retries} attempts")

Error Context and Details

Error Messages

The SDK provides detailed error messages with context:

from upstox_totp import UpstoxTOTP, ConfigurationError

try:
    upx = UpstoxTOTP()
except ConfigurationError as e:
    # Error messages include specific missing variables
    print(e)  # "Missing required environment variables: UPSTOX_USERNAME, UPSTOX_PASSWORD"

Error Details

Many errors include additional details:

from upstox_totp import UpstoxTOTP, UpstoxError

try:
    upx = UpstoxTOTP()
    response = upx.app_token.get_access_token()
except UpstoxError as e:
    if e.details:
        print("Error details:")
        for key, value in e.details.items():
            print(f"  {key}: {value}")

Troubleshooting Suggestions

Errors often include helpful suggestions:

from upstox_totp import UpstoxTOTP, UpstoxError

try:
    upx = UpstoxTOTP()
    response = upx.app_token.get_access_token()
except UpstoxError as e:
    print(f"Error: {e}")

    if e.suggestions:
        print("\nTroubleshooting suggestions:")
        for i, suggestion in enumerate(e.suggestions, 1):
            print(f"{i}. {suggestion}")

Common Error Scenarios

Missing Environment Variables

# Error: ConfigurationError
# Message: Missing required environment variables: UPSTOX_USERNAME
# Solution: Set the missing environment variable

import os
os.environ['UPSTOX_USERNAME'] = '9876543210'

Invalid Username Format

# Error: ValidationError
# Message: Username must be exactly 10 digits
# Solution: Use your 10-digit mobile number

from upstox_totp import UpstoxTOTP
from pydantic import SecretStr

upx = UpstoxTOTP(
    username="9876543210",  # Must be 10 digits
    password=SecretStr("password"),
    # ... other fields
)

Invalid TOTP Secret

# Error: ValidationError
# Message: Invalid TOTP secret format
# Solution: Ensure secret is base32 encoded, no spaces

# Wrong: "JBSW Y3DP EHPK 3PXP"
# Right: "JBSWY3DPEHPK3PXP"

Network Connection Issues

import requests
from upstox_totp import UpstoxTOTP, UpstoxError

try:
    upx = UpstoxTOTP()
    response = upx.app_token.get_access_token()
except requests.ConnectionError:
    print("Network connection error")
    print("Check your internet connection")
except requests.Timeout:
    print("Request timeout")
    print("Try again or increase timeout")

Authentication Failures

from upstox_totp import UpstoxTOTP

upx = UpstoxTOTP()
response = upx.app_token.get_access_token()

if not response.success:
    error = response.error

    if "invalid_credentials" in str(error):
        print("Invalid username/password")
    elif "invalid_totp" in str(error):
        print("Invalid TOTP code")
        print("Check your TOTP secret configuration")
    elif "invalid_pin" in str(error):
        print("Invalid PIN code")

Client ID / OAuth Issues

from upstox_totp import UpstoxTOTP

upx = UpstoxTOTP()
response = upx.app_token.get_access_token()

if not response.success:
    error = response.error

    if "invalid_client" in str(error):
        print("Invalid client ID or secret")
        print("Check your Upstox Developer App credentials")
    elif "redirect_uri_mismatch" in str(error):
        print("Redirect URI mismatch")
        print("Ensure redirect_uri matches your app settings")

Custom Error Handling

Custom Exception Classes

from upstox_totp.errors import UpstoxError

class TokenExpiredError(UpstoxError):
    """Raised when access token has expired."""
    pass

class RateLimitError(UpstoxError):
    """Raised when rate limit is exceeded."""
    pass

def enhanced_get_token():
    upx = UpstoxTOTP()
    response = upx.app_token.get_access_token()

    if not response.success:
        error = response.error

        if "token_expired" in str(error):
            raise TokenExpiredError("Access token has expired")
        elif "rate_limit" in str(error):
            raise RateLimitError("Rate limit exceeded")
        else:
            raise UpstoxError(f"Token generation failed: {error}")

    return response.data.access_token

Error Logging

import logging
from upstox_totp import UpstoxTOTP, UpstoxError

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

def logged_token_generation():
    try:
        logger.info("Starting token generation...")
        upx = UpstoxTOTP()
        response = upx.app_token.get_access_token()

        if response.success:
            logger.info("Token generated successfully")
            return response.data.access_token
        else:
            logger.error(f"Token generation failed: {response.error}")
            return None

    except UpstoxError as e:
        logger.error(f"Upstox error: {e}", exc_info=True)
        return None
    except Exception as e:
        logger.error(f"Unexpected error: {e}", exc_info=True)
        return None

Error Recovery Strategies

Automatic Retry

from functools import wraps
import time

def retry_on_error(max_retries=3, delay=1, backoff=2):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            retries = 0
            current_delay = delay

            while retries < max_retries:
                try:
                    return func(*args, **kwargs)
                except (ConnectionError, TimeoutError) as e:
                    retries += 1
                    if retries >= max_retries:
                        raise e

                    time.sleep(current_delay)
                    current_delay *= backoff

            return func(*args, **kwargs)
        return wrapper
    return decorator

@retry_on_error(max_retries=3, delay=2)
def resilient_token_generation():
    upx = UpstoxTOTP()
    response = upx.app_token.get_access_token()

    if not response.success:
        raise Exception(f"Token generation failed: {response.error}")

    return response.data.access_token

Fallback Mechanisms

from upstox_totp import UpstoxTOTP, UpstoxError

def get_token_with_fallback():
    """Try multiple strategies to get a token."""

    # Strategy 1: Normal generation
    try:
        upx = UpstoxTOTP()
        response = upx.app_token.get_access_token()
        if response.success:
            return response.data.access_token
    except Exception as e:
        print(f"Strategy 1 failed: {e}")

    # Strategy 2: Reset session and retry
    try:
        upx.reset_session()
        response = upx.app_token.get_access_token()
        if response.success:
            return response.data.access_token
    except Exception as e:
        print(f"Strategy 2 failed: {e}")

    # Strategy 3: New client instance
    try:
        upx = UpstoxTOTP()
        response = upx.app_token.get_access_token()
        if response.success:
            return response.data.access_token
    except Exception as e:
        print(f"Strategy 3 failed: {e}")

    raise Exception("All token generation strategies failed")

Debugging Errors

Enable Debug Mode

from upstox_totp import UpstoxTOTP

# Enable debug logging
upx = UpstoxTOTP(debug=True)

# Or via environment variable
import os
os.environ['UPSTOX_DEBUG'] = 'true'
upx = UpstoxTOTP()

Capture Request/Response

import logging
from upstox_totp import UpstoxTOTP

# Enable HTTP debugging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)

upx = UpstoxTOTP(debug=True)

Inspect Session State

from upstox_totp import UpstoxTOTP

upx = UpstoxTOTP()

# Inspect session
print(f"Session cookies: {dict(upx.session.cookies)}")
print(f"Session headers: {dict(upx.session.headers)}")

try:
    response = upx.app_token.get_access_token()
except Exception as e:
    print(f"Error occurred: {e}")
    print(f"Session state: {dict(upx.session.cookies)}")

Testing Error Conditions

Mock Errors for Testing

import pytest
from unittest.mock import patch
from upstox_totp import UpstoxTOTP, UpstoxError

def test_configuration_error():
    with patch.dict('os.environ', {}, clear=True):
        with pytest.raises(ConfigurationError):
            UpstoxTOTP()

def test_network_error():
    with patch('requests.Session.post') as mock_post:
        mock_post.side_effect = ConnectionError("Network error")

        upx = UpstoxTOTP()
        with pytest.raises(ConnectionError):
            upx.app_token.get_access_token()

Error Monitoring

Health Checks

from upstox_totp import UpstoxTOTP, ConfigurationError

def health_check():
    """Check if the SDK is properly configured."""
    try:
        upx = UpstoxTOTP()
        return {"status": "healthy", "configuration": "valid"}
    except ConfigurationError as e:
        return {"status": "unhealthy", "error": str(e)}
    except Exception as e:
        return {"status": "error", "error": str(e)}

Metrics Collection

import time
from collections import defaultdict
from upstox_totp import UpstoxTOTP, UpstoxError

class ErrorMetrics:
    def __init__(self):
        self.error_counts = defaultdict(int)
        self.last_errors = []

    def record_error(self, error):
        error_type = type(error).__name__
        self.error_counts[error_type] += 1
        self.last_errors.append({
            'type': error_type,
            'message': str(error),
            'timestamp': time.time()
        })

        # Keep only last 100 errors
        if len(self.last_errors) > 100:
            self.last_errors.pop(0)

    def get_summary(self):
        return {
            'error_counts': dict(self.error_counts),
            'last_errors': self.last_errors[-10:]  # Last 10 errors
        }

metrics = ErrorMetrics()

def monitored_token_generation():
    try:
        upx = UpstoxTOTP()
        response = upx.app_token.get_access_token()
        return response
    except Exception as e:
        metrics.record_error(e)
        raise

Best Practices

  1. Always handle specific exception types before generic ones

  2. Provide meaningful error messages to users

  3. Log errors with sufficient context for debugging

  4. Don’t retry configuration/validation errors - fix them instead

  5. Use exponential backoff for retries

  6. Monitor error rates in production

  7. Test error conditions thoroughly

  8. Document expected errors for API users

  9. Clean up resources even when errors occur

  10. Validate input early to provide better error messages

See Also