Appearance
Error Handling
Comprehensive guide to handling errors in the Urban Sky SDK.
Error Types
The error event delivers a payload with two fields — there is no numeric or symbolic error code on it. Branch on message (and on error for the reconnect sentinel).
| Field | Type | Description |
|---|---|---|
message | string | What the SDK was doing when it failed, e.g. Authentication failed |
error | string | The underlying cause, stringified. Also the literal RECONNECT_FAILED sentinel |
Messages the SDK emits
message | When it happens | Recovery strategy |
|---|---|---|
Authentication failed | Token rejected during auth/refresh | Verify the API token |
Max reconnection attempts (N) reached | Reconnect budget exhausted | Recreate the SDK, check the network |
All reconnection attempts failed | Every backoff attempt errored | Recreate the SDK, check the network |
Subscription error | Channel subscription rejected | Verify token scopes |
Failed to process publication | A received message could not be parsed | Log and continue |
Failed to process balloon update | A balloon update could not be parsed | Log and continue |
Failed to process unassigned devices update | An unassigned-devices message failed | Log and continue |
In JavaScript the same payload arrives as { message, error }; the exact strings are identical across both languages.
Basic Error Handling
Connection Errors
Handle connection failures gracefully:
javascript
const sdk = await UrbanSkySDK.init({
apiToken: 'your-token',
baseUrl: 'https://api.ops.atmosys.com',
})
// Handle connection errors. The payload is { message, error } — no code field.
sdk.on('error', ({ message, error }) => {
console.error('SDK Error:', message, '-', error)
if (message === 'Authentication failed') {
console.error('❌ Authentication failed. Verify your API token.')
} else if (error === 'RECONNECT_FAILED') {
console.error('❌ Reconnect budget exhausted. Recreate the SDK.')
} else if (message.startsWith('All reconnection attempts failed')) {
console.log('🔄 Reconnection failed. Check your network.')
} else if (message === 'Subscription error') {
console.error('🚫 Subscription rejected. Check your token scopes.')
} else {
// Parse failures ("Failed to process ...") are non-fatal — log and continue.
console.warn('❓ Non-fatal SDK error:', message)
}
})
console.log('✅ SDK initialized and connected successfully')python
# 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)
sdk = await UrbanSkySDK.init({
'apiToken': 'your-token',
'baseUrl': 'https://api.ops.atmosys.com'
})
# The error payload is a dict: {'message': ..., 'error': ...}
def on_error(payload):
message = payload['message']
cause = payload['error']
print(f"SDK Error: {message} - {cause}")
if message == 'Authentication failed':
print("❌ Authentication failed. Verify your API token.")
elif cause == 'RECONNECT_FAILED':
print("❌ Reconnect budget exhausted. Recreate the SDK.")
elif message.startswith('All reconnection attempts failed'):
print("🔄 Reconnection failed. Check your network.")
elif message == 'Subscription error':
print("🚫 Subscription rejected. Check your token scopes.")
else:
# Parse failures ("Failed to process ...") are non-fatal - log and continue.
print(f"❓ Non-fatal SDK error: {message}")
sdk.on('error', on_error)Handling Disconnections
The SDK automatically attempts to reconnect when disconnected. You can monitor the connection status:
javascript
// Track connection state
let isConnected = false
sdk.on('connected', () => {
isConnected = true
console.log('✅ Connected to Urban Sky')
})
sdk.on('disconnected', () => {
isConnected = false
console.log('❌ Disconnected from Urban Sky')
})
// Check connection before operations
function sendData(data) {
if (!isConnected) {
console.warn('Not connected. Data will be queued.')
return
}
// Process data
}python
# Track connection state
is_connected = False
def on_connected(_):
global is_connected
is_connected = True
print("✅ Connected to Urban Sky")
def on_disconnected(_):
global is_connected
is_connected = False
print("❌ Disconnected from Urban Sky")
sdk.on('connected', on_connected)
sdk.on('disconnected', on_disconnected)
# Check connection before operations
def send_data(data):
if not is_connected:
print("Not connected. Data will be queued.")
return
# Process dataError Recovery Patterns
Retry Logic
Implement simple retry logic for transient errors:
javascript
async function connectWithRetry(maxAttempts = 3) {
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
await sdk.connect()
console.log('✅ Connected successfully')
return true
} catch (error) {
console.error(`Attempt ${attempt} failed: ${error.message}`)
if (attempt < maxAttempts) {
const delay = attempt * 2000 // Exponential backoff
console.log(`Retrying in ${delay}ms...`)
await new Promise(resolve => setTimeout(resolve, delay))
}
}
}
console.error('❌ All connection attempts failed')
return false
}
// Usage
const connected = await connectWithRetry()
if (!connected) {
console.error('Unable to establish connection')
}python
import asyncio
async def connect_with_retry(max_attempts=3):
for attempt in range(1, max_attempts + 1):
try:
await sdk.connect()
print("✅ Connected successfully")
return True
except Exception as error:
print(f"Attempt {attempt} failed: {error}")
if attempt < max_attempts:
delay = attempt * 2 # Exponential backoff
print(f"Retrying in {delay} seconds...")
await asyncio.sleep(delay)
print("❌ All connection attempts failed")
return False
# Usage
connected = await connect_with_retry()
if not connected:
print("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
if not hasattr(update, 'balloon_id') or not hasattr(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
- Always implement error handlers - Don't let errors crash your application
- Log errors appropriately - Include context for debugging
- Use the SDK's automatic reconnection - Don't implement your own unless necessary
- Handle authentication errors differently - These require user action
- Implement data validation - Verify data structure before processing
Getting Help
If you encounter persistent errors:
- Check the error code and message
- Verify your API token is valid
- Ensure you have a stable internet connection
- 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