LogoRecal
JS/TS SDK

Error Handling

Handle errors and exceptions in the Recal SDK.

Understanding Error Handling

The Recal SDK provides a comprehensive error handling system through the RecalError class. All SDK methods throw typed errors that you can catch and handle appropriately in your application.


RecalError Class

The SDK uses a custom RecalError class that extends the native JavaScript Error with additional properties:

class RecalError extends Error {
    statusCode?: number   // HTTP status code (404, 400, 500, etc.)
    details?: unknown     // Additional error details from the API
}

Basic Error Handling

Wrap SDK calls in try-catch blocks to handle errors:

import { Recal, RecalError } from 'recal-sdk'

const recal = new Recal({ token: process.env.RECAL_TOKEN })

try {
    const user = await recal.users.get('user_123')
    console.log('User found:', user)
} catch (error) {
    if (error instanceof RecalError) {
        console.error('Recal API Error:', error.message)
        console.error('Status Code:', error.statusCode)
        console.error('Details:', error.details)
    } else {
        console.error('Unexpected error:', error)
    }
}

Common Error Status Codes

400 Bad Request

Invalid request parameters or missing required fields.

try {
    await recal.events.createEvent('user_id', 'google', 'primary', {
        subject: 'Meeting',
        // Missing required 'start' and 'end' fields
    })
} catch (error) {
    if (error instanceof RecalError && error.statusCode === 400) {
        console.error('Invalid request:', error.message)
        // Handle validation errors
    }
}

401 Unauthorized

Invalid or missing API token.

const recal = new Recal({ token: 'invalid_token' })

try {
    await recal.users.list()
} catch (error) {
    if (error instanceof RecalError && error.statusCode === 401) {
        console.error('Authentication failed - check your API token')
        // Prompt user to re-authenticate or check token
    }
}

404 Not Found

Resource doesn't exist (user, organization, event, etc.).

try {
    await recal.users.get('nonexistent_user')
} catch (error) {
    if (error instanceof RecalError && error.statusCode === 404) {
        console.error('User not found')
        // Handle missing resource
    }
}

429 Too Many Requests

Rate limit exceeded.

try {
    await recal.calendar.listEvents('user_id', {
        start: '2024-01-01T00:00:00Z',
        end: '2024-12-31T23:59:59Z'
    })
} catch (error) {
    if (error instanceof RecalError && error.statusCode === 429) {
        console.error('Rate limit exceeded - please retry later')
        // Implement exponential backoff
    }
}

500 Internal Server Error

Server-side error.

try {
    await recal.oauth.verifyCode('google', { code: 'auth_code', state: 'state' })
} catch (error) {
    if (error instanceof RecalError && error.statusCode === 500) {
        console.error('Server error - please try again')
        // Log error and notify monitoring system
    }
}

Error Handling Patterns

Centralized Error Handler

Create a reusable error handler for consistent error handling:

function handleRecalError(error: unknown, context: string) {
    if (error instanceof RecalError) {
        console.error(`[${context}] Recal API Error:`, {
            message: error.message,
            statusCode: error.statusCode,
            details: error.details
        })

        // Handle specific status codes
        switch (error.statusCode) {
            case 400:
                return { error: 'Invalid request', retry: false }
            case 401:
                return { error: 'Authentication failed', retry: false }
            case 404:
                return { error: 'Resource not found', retry: false }
            case 429:
                return { error: 'Rate limit exceeded', retry: true }
            case 500:
                return { error: 'Server error', retry: true }
            default:
                return { error: 'Unknown error', retry: false }
        }
    }

    console.error(`[${context}] Unexpected error:`, error)
    return { error: 'Unexpected error', retry: false }
}

// Usage
try {
    await recal.users.create('user_123')
} catch (error) {
    const result = handleRecalError(error, 'User Creation')
    if (result.retry) {
        // Implement retry logic
    }
}

Retry with Exponential Backoff

Handle transient errors with automatic retries:

async function withRetry<T>(
    fn: () => Promise<T>,
    maxRetries = 3,
    initialDelay = 1000
): Promise<T> {
    let lastError: Error

    for (let attempt = 0; attempt < maxRetries; attempt++) {
        try {
            return await fn()
        } catch (error) {
            lastError = error as Error

            // Only retry on specific errors
            if (error instanceof RecalError) {
                const shouldRetry = [429, 500, 503].includes(error.statusCode || 0)

                if (!shouldRetry || attempt === maxRetries - 1) {
                    throw error
                }

                const delay = initialDelay * Math.pow(2, attempt)
                console.log(`Retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`)
                await new Promise(resolve => setTimeout(resolve, delay))
            } else {
                throw error
            }
        }
    }

    throw lastError!
}

// Usage
const user = await withRetry(() => recal.users.get('user_123'))

Graceful Degradation

Handle errors gracefully without breaking your application:

async function getUserCalendars(userId: string) {
    try {
        return await recal.calendar.list(userId)
    } catch (error) {
        if (error instanceof RecalError) {
            console.warn('Failed to fetch calendars:', error.message)
            return [] // Return empty array as fallback
        }
        throw error
    }
}

Best Practices

  1. Always Use Try-Catch: Wrap all SDK calls in try-catch blocks
  2. Check Error Types: Use instanceof RecalError to identify SDK errors
  3. Log Error Details: Include statusCode and details in logs for debugging
  4. Handle Specific Codes: Implement different logic for different status codes
  5. Implement Retries: Retry transient errors (429, 500) with exponential backoff
  6. User-Friendly Messages: Convert technical errors to user-friendly messages
  7. Monitor Errors: Track error rates and patterns in your monitoring system
  8. Validate Input: Catch validation errors early before making API calls

Type Safety

TypeScript provides type checking for error handling:

import { Recal, RecalError } from 'recal-sdk'

async function safeUserFetch(userId: string) {
    const recal = new Recal({ token: process.env.RECAL_TOKEN })

    try {
        const user = await recal.users.get(userId)
        return { success: true, data: user }
    } catch (error) {
        // Type guard ensures proper error handling
        if (error instanceof RecalError) {
            return {
                success: false,
                error: error.message,
                statusCode: error.statusCode
            }
        }
        return { success: false, error: 'Unknown error' }
    }
}

  • See Users for user-specific operations
  • See Events for event-specific operations
  • See OAuth for OAuth-specific error handling

On this page