Skip to content

Error Handling Examples

This page demonstrates best practices for handling errors and edge cases when using the Urban Sky SDK.

Basic Error Handling

JavaScript

javascript
// Load the SDK
const response = await fetch('https://sdk.atmosys.com/runtime/js/current/loader.js')
eval(await response.text())

const sdk = await UrbanSkySDK.init({
  apiToken: 'your-api-token-here',
  debug: true,
})

// Handle connection errors
sdk.on('error', error => {
  console.error('SDK Error:', error)

  switch (error.code) {
    case 'AUTH_INVALID_TOKEN':
      console.error('❌ Invalid API token')
      // Stop trying to reconnect
      break

    case 'AUTH_INSUFFICIENT_PERMISSIONS':
      console.error('❌ Token lacks SDK permissions')
      // Check token permissions in dashboard
      break

    case 'CONNECTION_FAILED':
      console.error('❌ Connection failed - will retry')
      // SDK will auto-retry
      break

    case 'SERVICE_UNAVAILABLE':
      console.error('❌ Service temporarily unavailable')
      // Implement exponential backoff
      break

    default:
      console.error('❌ Unknown error:', error.message)
  }
})

// Handle connection state changes
sdk.on('connected', () => {
  console.log('✅ Connected to Urban Sky')
})

sdk.on('disconnected', () => {
  console.log('⚠️ Disconnected from Urban Sky')
})

// Connect with error handling
try {
  await sdk.connect()
} catch (error) {
  console.error('Failed to connect:', error)
  // Handle initial connection failure
}

Python

python
import asyncio
import logging

# Load the SDK (requires `pip install requests`)
# The SDK also requires centrifuge-python: pip install centrifuge-python
import requests
exec(requests.get('https://sdk.atmosys.com/runtime/py/current/loader.py').text)

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

async def main():
    # Initialize and connect
    sdk = await UrbanSkySDK.init({
        'apiToken': 'your-api-token-here'
    })

    # Error event handler
    def on_error(error):
        if isinstance(error, dict):
            error_code = error.get('error', 'UNKNOWN')
            error_message = error.get('message', str(error))
        else:
            error_code = 'UNKNOWN'
            error_message = str(error)

        logger.error(f"SDK Error: {error_code} - {error_message}")

        if error_code == 'AUTH_INVALID_TOKEN':
            logger.error("❌ Invalid API token")

        elif error_code == 'AUTH_INSUFFICIENT_PERMISSIONS':
            logger.error("❌ Token lacks SDK permissions")

        elif error_code == 'CONNECTION_FAILED':
            logger.error("❌ Connection failed - will retry")
            # SDK will auto-retry

        elif error_code == 'SERVICE_UNAVAILABLE':
            logger.error("❌ Service temporarily unavailable")

        else:
            logger.error(f"❌ Unknown error: {error_message}")

    # Connection state handlers (handlers always receive one payload argument)
    def on_connected(_payload):
        logger.info("✅ Connected to Urban Sky")

    def on_disconnected(_payload):
        logger.warning("⚠️ Disconnected from Urban Sky")

    # Register event handlers
    sdk.on('error', on_error)
    sdk.on('connected', on_connected)
    sdk.on('disconnected', on_disconnected)

    # Keep the connection alive so handlers can fire
    try:
        while True:
            await asyncio.sleep(1)
    except KeyboardInterrupt:
        await sdk.disconnect()

asyncio.run(main())

Simple Retry Logic

For basic retry functionality when connections fail:

javascript
async function initializeWithRetry(config, maxAttempts = 3) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      const sdk = await UrbanSkySDK.init(config)
      console.log('✅ Connected successfully')
      return sdk
    } catch (error) {
      console.error(`Attempt ${attempt} failed: ${error.message}`)

      // Don't retry on authentication errors
      if (error.code === 'AUTH_INVALID_TOKEN' || error.code === 'AUTH_INSUFFICIENT_PERMISSIONS') {
        console.error('❌ Authentication failed - not retrying')
        throw error
      }

      if (attempt < maxAttempts) {
        const delay = attempt * 2000 // Simple backoff: 2s, 4s, 6s
        console.log(`Retrying in ${delay}ms...`)
        await new Promise(resolve => setTimeout(resolve, delay))
      }
    }
  }

  console.error('❌ All connection attempts failed')
  return null
}

// Usage
const sdk = await initializeWithRetry({ apiToken: 'your-token' })
if (!sdk) {
  console.error('Unable to establish connection')
}

Handling Data Processing Errors

Implement error boundaries for data processing:

javascript
sdk.on('balloon:update', update => {
  try {
    // Process update
    processUpdate(update)
  } catch (error) {
    console.error('Error processing update:', error)
    // Log error but don't crash the application
    logError(error, update)
  }
})

function processUpdate(update) {
  // Validate data
  if (!update.balloonId || !update.devices) {
    throw new Error('Invalid update structure')
  }

  // Process each device safely
  update.devices.forEach(device => {
    try {
      processDevice(device)
    } catch (error) {
      console.error(`Error processing device ${device.deviceId}:`, error)
    }
  })
}
python
def on_balloon_update(update):
    try:
        # Process update
        process_update(update)
    except Exception as error:
        print(f"Error processing update: {error}")
        # Log error but don't crash the application
        log_error(error, update)

def process_update(update):
    # Validate data - `update` is a BalloonUpdate dataclass, not a dict
    if not update.balloon_id or not update.devices:
        raise ValueError("Invalid update structure")

    # Process each device safely
    for device in update.devices:
        try:
            process_device(device)
        except Exception as error:
            print(f"Error processing device {device.device_id}: {error}")

sdk.on('balloon:update', on_balloon_update)

Best Practices

  1. Always implement error handlers - Don't let errors crash your application
  2. Log errors appropriately - Include context for debugging
  3. Use the SDK's automatic reconnection - Don't implement your own unless necessary
  4. Handle authentication errors differently - These require user action
  5. Implement data validation - Verify data structure before processing

Getting Help

If you encounter persistent errors:

  1. Check the error code and message
  2. Verify your API token is valid
  3. Ensure you have a stable internet connection
  4. Contact Urban Sky support at support@atmosys.com with:
    • Your organization name
    • The error code and message
    • When the error occurred
    • Any relevant context about what you were trying to do

Next Steps