Skip to main content
The Recall AI SDK includes built-in error handling to help you gracefully manage API errors and network issues.

Error handling approach

The SDK uses a try-catch wrapper around all API requests. Instead of throwing exceptions, SDK methods return either the successful response data or an error object.

Error response structure

When an error occurs, methods return a RecallError object:
interface RecallError {
  error: any;
  status: number;
}

Handling errors

Check if a response is an error by verifying the presence of the error property:
const result = await recall.bot.create({
  meeting_url: 'https://meet.google.com/abc-defg-hij'
});

if ('error' in result) {
  // Handle error
  console.error(`Error: ${result.status}`, result.error);
} else {
  // Success - use result.data
  console.log('Bot created:', result.id);
}
All SDK methods return a promise that resolves to either the response data or a RecallError object. Errors are never thrown, so you don’t need traditional try-catch blocks.

How error handling works

The SDK wraps all HTTP requests with the recallRequestTryCatchWrapper function:
// From try-catch-wrapper.ts
const recallRequestTryCatchWrapper = async <T>(func: () => Promise<any>): Promise<T | RecallError> => {
  try {
    const response = await func();
    return response.data;
  } catch (e: any) {
    return { error: e.response.data, status: e.response.statusCode };
  }
};
This wrapper:
  1. Executes the API request
  2. Returns response.data on success
  3. Catches errors and returns a RecallError object instead of throwing

Common error types

Authentication errors

Status code: 401 Unauthorized Occurs when your API key is invalid or missing.
const result = await recall.bot.list({});

if ('error' in result && result.status === 401) {
  console.error('Authentication failed. Check your API key.');
}

Permission errors

Status code: 403 Forbidden Occurs when your API key doesn’t have permission for the requested operation.
if ('error' in result && result.status === 403) {
  console.error('Insufficient permissions for this operation.');
}

Resource not found

Status code: 404 Not Found Occurs when requesting a resource that doesn’t exist.
const result = await recall.bot.retrieve({ id: 'invalid-bot-id' });

if ('error' in result && result.status === 404) {
  console.error('Bot not found.');
}

Validation errors

Status code: 400 Bad Request Occurs when request parameters are invalid or missing required fields.
if ('error' in result && result.status === 400) {
  console.error('Invalid request:', result.error);
}

Type-safe error handling

For TypeScript users, you can create a type guard to check for errors:
function isRecallError(result: any): result is RecallError {
  return 'error' in result && 'status' in result;
}

const result = await recall.bot.create(params);

if (isRecallError(result)) {
  // TypeScript knows result is RecallError
  console.error(`Error ${result.status}:`, result.error);
} else {
  // TypeScript knows result is CreateResponse
  console.log('Bot ID:', result.id);
}

Best practices

Every SDK method can return an error object. Always check the response before accessing data properties.
const result = await recall.bot.retrieve({ id: botId });

if ('error' in result) {
  return; // Handle error
}

// Safe to access result properties
console.log(result.id);
The error object contains detailed information from the API. Log both the status code and error message for debugging.
if ('error' in result) {
  console.error('API Error:', {
    status: result.status,
    error: result.error
  });
}
For transient errors (like network timeouts or 5xx server errors), implement retry logic with exponential backoff.
async function createBotWithRetry(params: CreateParams, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const result = await recall.bot.create(params);
    
    if (!('error' in result)) {
      return result; // Success
    }
    
    // Retry on 5xx errors
    if (result.status >= 500 && i < maxRetries - 1) {
      await new Promise(resolve => setTimeout(resolve, 1000 * Math.pow(2, i)));
      continue;
    }
    
    return result; // Return error after retries exhausted
  }
}
Different status codes require different handling strategies. Use a switch statement or if-else chain to handle errors appropriately.
if ('error' in result) {
  switch (result.status) {
    case 401:
      // Refresh credentials or redirect to login
      break;
    case 403:
      // Show permission denied message
      break;
    case 404:
      // Resource not found
      break;
    case 429:
      // Rate limit - implement backoff
      break;
    default:
      // Generic error handling
      break;
  }
}

Error handling in production

For production applications, implement comprehensive error handling:
import { Recall, RecallError } from 'recall_sdk';

class RecallService {
  private recall: Recall;
  
  constructor() {
    this.recall = new Recall({
      apiKey: process.env.RECALL_API_KEY!,
      region: process.env.RECALL_REGION || 'us-east-2'
    });
  }
  
  async createBot(meetingUrl: string) {
    const result = await this.recall.bot.create({
      meeting_url: meetingUrl
    });
    
    if ('error' in result) {
      // Log to monitoring service
      this.logError('createBot', result);
      
      // Return user-friendly error message
      throw new Error(this.getUserFriendlyMessage(result));
    }
    
    return result;
  }
  
  private logError(operation: string, error: RecallError) {
    console.error(`Recall API Error in ${operation}:`, {
      status: error.status,
      error: error.error,
      timestamp: new Date().toISOString()
    });
    
    // Send to error tracking service (e.g., Sentry, DataDog)
    // errorTracker.captureException(error);
  }
  
  private getUserFriendlyMessage(error: RecallError): string {
    switch (error.status) {
      case 401:
        return 'Authentication failed. Please check your API credentials.';
      case 403:
        return 'You do not have permission to perform this action.';
      case 404:
        return 'The requested resource was not found.';
      case 429:
        return 'Rate limit exceeded. Please try again later.';
      case 500:
      case 502:
      case 503:
        return 'Service temporarily unavailable. Please try again later.';
      default:
        return 'An unexpected error occurred. Please try again.';
    }
  }
}
Integrate with error monitoring services like Sentry or DataDog to track and analyze API errors in production.

Build docs developers (and LLMs) love