Skip to main content

Error Handling

The Raptor SDK provides comprehensive error handling with typed exceptions and detailed error information.

Error Types

RaptorAPIError

API errors (4xx, 5xx responses):
import Raptor, { RaptorAPIError } from '@raptor-data/ts-sdk';

const raptor = new Raptor({ apiKey: process.env.RAPTOR_API_KEY });

try {
  const result = await raptor.process('document.pdf');
} catch (error) {
  if (error instanceof RaptorAPIError) {
    console.error(`API Error ${error.statusCode}: ${error.message}`);
    console.error('Response:', error.response);
  }
}
Properties:
statusCode
number
HTTP status code (400, 401, 404, etc.)
message
string
Error message from the API
response
object
Full API response body

RaptorError

Client-side errors (validation, network, etc.):
import Raptor, { RaptorError } from '@raptor-data/ts-sdk';

try {
  const result = await raptor.process('document.pdf');
} catch (error) {
  if (error instanceof RaptorError) {
    console.error(`Client Error: ${error.message}`);
  }
}

Common Errors

400 Bad Request

Invalid input or parameters:
try {
  const result = await raptor.process('document.pdf', {
    chunkSize: 5000  // Too large (max 2048)
  });
} catch (error) {
  if (error instanceof RaptorAPIError && error.statusCode === 400) {
    console.error('Invalid parameters:', error.message);
    // Example: "chunk_size must be between 128 and 2048"
  }
}
Common causes:
  • Invalid chunk size (not in range 128-2048)
  • Invalid chunk overlap (not in range 0-512)
  • Invalid file type (not in allowed MIME types)
  • Invalid UUID format

401 Unauthorized

Invalid or missing API key:
try {
  const result = await raptor.process('document.pdf');
} catch (error) {
  if (error instanceof RaptorAPIError && error.statusCode === 401) {
    console.error('Authentication failed');
    console.error('Check your API key');

    // Verify API key is set
    console.log('API Key:', process.env.RAPTOR_API_KEY ? 'Set' : 'Missing');
  }
}
Solutions:
  • Verify API key is correct
  • Check environment variable is loaded
  • Ensure API key starts with rd_live_ or rd_test_

404 Not Found

Resource not found:
try {
  const document = await raptor.getDocument('invalid-id');
} catch (error) {
  if (error instanceof RaptorAPIError && error.statusCode === 404) {
    console.error('Document not found');
    // Handle missing document
  }
}
Common causes:
  • Invalid document ID
  • Document was deleted
  • Document belongs to different user

413 Request Entity Too Large

File too large:
try {
  const result = await raptor.process('huge-file.pdf');
} catch (error) {
  if (error instanceof RaptorAPIError && error.statusCode === 413) {
    console.error('File too large');
    console.error('Maximum file size: 100MB');

    // Suggest splitting or compressing
    suggestFileSplit();
  }
}

429 Too Many Requests

Rate limit exceeded:
try {
  const result = await raptor.process('document.pdf');
} catch (error) {
  if (error instanceof RaptorAPIError && error.statusCode === 429) {
    console.error('Rate limit exceeded');

    // Check rate limit headers
    const retryAfter = error.response?.headers?.['retry-after'];
    console.log(`Retry after: ${retryAfter} seconds`);

    // Wait and retry
    await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
    return await raptor.process('document.pdf');
  }
}

500 Internal Server Error

Server error:
try {
  const result = await raptor.process('document.pdf');
} catch (error) {
  if (error instanceof RaptorAPIError && error.statusCode === 500) {
    console.error('Server error');
    console.error('Please try again later');

    // Log for support
    logErrorToSupport(error);
  }
}

503 Service Unavailable

Service temporarily unavailable:
try {
  const result = await raptor.process('document.pdf');
} catch (error) {
  if (error instanceof RaptorAPIError && error.statusCode === 503) {
    console.error('Service unavailable');

    // Retry with exponential backoff
    await retryWithBackoff(() => raptor.process('document.pdf'));
  }
}

Network Errors

Handle network failures:
try {
  const result = await raptor.process('document.pdf');
} catch (error) {
  if (error instanceof RaptorError) {
    if (error.message.includes('ECONNREFUSED')) {
      console.error('Cannot connect to API');
      console.error('Check your internet connection');
    } else if (error.message.includes('ETIMEDOUT')) {
      console.error('Request timed out');
      console.error('Try increasing timeout:');
      console.log('new Raptor({ timeout: 600000 })');
    }
  }
}

Timeout Errors

Handle processing timeouts:
try {
  const result = await raptor.process('large-document.pdf', {
    pollTimeout: 300000  // 5 minutes
  });
} catch (error) {
  if (error instanceof RaptorError && error.message.includes('timeout')) {
    console.error('Processing timeout');

    // Option 1: Increase timeout
    const result = await raptor.process('large-document.pdf', {
      pollTimeout: 600000  // 10 minutes
    });

    // Option 2: Process async
    const result = await raptor.process('large-document.pdf', {
      wait: false  // Don't wait for completion
    });

    // Poll manually
    const variant = await raptor.getVariant(result.variantId);
    console.log(`Status: ${variant.status}`);
  }
}

Validation Errors

Handle file validation errors:
async function uploadDocument(file: File) {
  // Client-side validation
  if (file.size > 100 * 1024 * 1024) {
    throw new Error('File too large (max 100MB)');
  }

  const allowedTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
  if (!allowedTypes.includes(file.type)) {
    throw new Error(`Invalid file type: ${file.type}`);
  }

  try {
    const result = await raptor.process(file);
    return result;
  } catch (error) {
    if (error instanceof RaptorAPIError && error.statusCode === 400) {
      // Handle specific validation errors
      if (error.message.includes('mime type')) {
        throw new Error('File type not supported');
      }
    }
    throw error;
  }
}

Comprehensive Error Handler

import Raptor, { RaptorError, RaptorAPIError } from '@raptor-data/ts-sdk';

async function processDocumentSafely(filePath: string) {
  try {
    const result = await raptor.process(filePath);
    return result;
  } catch (error) {
    if (error instanceof RaptorAPIError) {
      // API errors
      switch (error.statusCode) {
        case 400:
          console.error('Invalid request:', error.message);
          break;
        case 401:
          console.error('Authentication failed. Check your API key.');
          break;
        case 404:
          console.error('Resource not found');
          break;
        case 413:
          console.error('File too large (max 100MB)');
          break;
        case 429:
          console.error('Rate limit exceeded. Please wait and try again.');
          const retryAfter = error.response?.headers?.['retry-after'] || 60;
          console.log(`Retry after ${retryAfter} seconds`);
          break;
        case 500:
        case 503:
          console.error('Server error. Please try again later.');
          break;
        default:
          console.error(`API Error ${error.statusCode}:`, error.message);
      }

      // Log full response for debugging
      console.error('Full response:', error.response);
    } else if (error instanceof RaptorError) {
      // Client errors
      console.error('Client error:', error.message);

      if (error.message.includes('timeout')) {
        console.error('Request timed out. Try increasing timeout.');
      } else if (error.message.includes('ECONNREFUSED')) {
        console.error('Cannot connect to API. Check your internet connection.');
      }
    } else {
      // Unknown error
      console.error('Unexpected error:', error);
    }

    // Re-throw or return null
    throw error;
  }
}

Retry Logic

Implement retry with exponential backoff:
async function processWithRetry(
  filePath: string,
  maxRetries = 3,
  baseDelay = 1000
) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await raptor.process(filePath);
    } catch (error) {
      const isLastAttempt = attempt === maxRetries - 1;

      if (error instanceof RaptorAPIError) {
        // Don't retry client errors (4xx)
        if (error.statusCode >= 400 && error.statusCode < 500) {
          throw error;
        }

        // Retry server errors (5xx) and rate limits
        if (!isLastAttempt) {
          const delay = baseDelay * Math.pow(2, attempt);
          console.log(`Attempt ${attempt + 1} failed. Retrying in ${delay}ms...`);
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
      }

      // Re-throw on last attempt
      throw error;
    }
  }
}

// Usage
try {
  const result = await processWithRetry('document.pdf');
  console.log('Success!');
} catch (error) {
  console.error('All retries failed');
}

Error Recovery

Graceful Degradation

async function processDocument(file: File) {
  try {
    // Try with advanced features
    return await raptor.process(file, {
      calculateQualityScores: true,
      tableContextGeneration: true,
      processImages: true
    });
  } catch (error) {
    if (error instanceof RaptorAPIError && error.statusCode === 500) {
      console.warn('Advanced features failed, trying basic processing');

      // Fall back to basic processing
      return await raptor.process(file, {
        calculateQualityScores: false,
        tableContextGeneration: false,
        processImages: false
      });
    }
    throw error;
  }
}

Cancel on Error

async function processWithCancel(file: File) {
  try {
    const result = await raptor.process(file, {
      wait: false  // Start async processing
    });

    // Monitor processing
    const variant = await raptor.getVariant(result.variantId);

    if (variant.status === 'failed') {
      console.error('Processing failed:', variant.error);

      // Cancel if needed
      await raptor.cancelProcessing(result.variantId);
      throw new Error('Processing failed');
    }

    return result;
  } catch (error) {
    console.error('Upload error:', error);
    throw error;
  }
}

Best Practices

Always catch errors: Wrap SDK calls in try-catch blocks to handle failures gracefully.
Don’t retry 4xx errors: Client errors (400-499) indicate invalid requests. Fix the issue instead of retrying.
Log errors for debugging: Log full error details (statusCode, message, response) to help troubleshoot issues.

Production Error Handling

import Raptor, { RaptorError, RaptorAPIError } from '@raptor-data/ts-sdk';

class DocumentProcessor {
  private raptor: Raptor;
  private logger: Logger;

  constructor(apiKey: string, logger: Logger) {
    this.raptor = new Raptor({ apiKey });
    this.logger = logger;
  }

  async process(file: File): Promise<ProcessResult | null> {
    try {
      const result = await this.raptor.process(file, {
        wait: true,
        chunkSize: 512
      });

      this.logger.info('Document processed', {
        documentId: result.documentId,
        chunks: result.chunks.length
      });

      return result;
    } catch (error) {
      // Log error
      this.logger.error('Document processing failed', {
        filename: file.name,
        error: error instanceof Error ? error.message : 'Unknown error'
      });

      // Handle specific errors
      if (error instanceof RaptorAPIError) {
        switch (error.statusCode) {
          case 429:
            // Rate limit - notify user
            this.notifyRateLimit();
            break;
          case 401:
            // Auth error - critical
            this.alertAuthFailure();
            break;
          case 500:
          case 503:
            // Server error - retry later
            await this.queueForRetry(file);
            break;
        }
      }

      // Return null instead of throwing
      return null;
    }
  }

  private notifyRateLimit() {
    // Send notification to user
  }

  private alertAuthFailure() {
    // Alert developers
  }

  private async queueForRetry(file: File) {
    // Add to retry queue
  }
}