or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

async-operations.mdauthentication.mdcache.mderrors.mdindex.mdlogging.mdtransport.mduser-agent.md
tile.json

errors.mddocs/

Error Handling

Comprehensive error system with specific error types for different failure scenarios, stack trace management, and detailed error information for debugging and monitoring.

Capabilities

Base Error Classes

Algolia Error:

/**
 * Base error class for all Algolia-related errors
 */
class AlgoliaError extends Error {
  /** Error name identifier */
  name: string;
  
  /**
   * Creates a new Algolia error
   * @param message - Error message
   * @param name - Error name/type
   */
  constructor(message: string, name: string);
}

Error with Stack Trace:

/**
 * Error class that includes request/response stack trace information
 */
class ErrorWithStackTrace extends AlgoliaError {
  /** Stack trace of requests that led to this error */
  stackTrace: StackFrame[];
  
  /**
   * Creates error with stack trace information
   * @param message - Error message
   * @param stackTrace - Array of request/response frames
   * @param name - Error name/type
   */
  constructor(message: string, stackTrace: StackFrame[], name: string);
}

Specific Error Types

API Error:

/**
 * Error from Algolia API with HTTP status code
 */
class ApiError extends ErrorWithStackTrace {
  /** HTTP status code from the API response */
  status: number;
  
  /**
   * Creates API error with status code
   * @param message - Error message from API
   * @param status - HTTP status code
   * @param stackTrace - Request/response stack trace
   * @param name - Error name (default: 'ApiError')
   */
  constructor(message: string, status: number, stackTrace: StackFrame[], name?: string);
}

Detailed API Error:

/**
 * API error with additional structured error details
 */
class DetailedApiError extends ApiError {
  /** Detailed error information */
  error: DetailedError;

  /**
   * Creates detailed API error
   * @param message - Error message
   * @param status - HTTP status code
   * @param error - Structured error details
   * @param stackTrace - Request/response stack trace
   */
  constructor(message: string, status: number, error: DetailedError, stackTrace: StackFrame[]);
}

interface DetailedError {
  /** Error code identifier */
  code: string;
  /** Optional detailed error information */
  details?: DetailedErrorWithMessage[] | DetailedErrorWithTypeID[];
}

interface DetailedErrorWithMessage {
  /** Error message */
  message: string;
  /** Error label/category */
  label: string;
}

interface DetailedErrorWithTypeID {
  /** Error identifier */
  id: string;
  /** Error type */
  type: string;
  /** Optional error name */
  name?: string;
}

Retry Error:

/**
 * Error when all retry attempts have been exhausted
 */
class RetryError extends ErrorWithStackTrace {
  /**
   * Creates retry exhausted error
   * @param stackTrace - Complete stack trace of all retry attempts
   */
  constructor(stackTrace: StackFrame[]);
}

Deserialization Error:

/**
 * Error when response content cannot be parsed as JSON
 */
class DeserializationError extends AlgoliaError {
  /** The response that failed to deserialize */
  response: Response;
  
  /**
   * Creates deserialization error
   * @param message - Error message (usually from JSON.parse)
   * @param response - Response that failed to parse
   */
  constructor(message: string, response: Response);
}

Index-Related Errors

Index Not Found Error:

/**
 * Error when specified index does not exist
 */
class IndexNotFoundError extends AlgoliaError {
  /**
   * Creates index not found error
   * @param indexName - Name of the index that was not found
   */
  constructor(indexName: string);
}

Index Already Exists Error:

/**
 * Error when trying to create an index that already exists
 */
class IndexAlreadyExistsError extends AlgoliaError {
  /**
   * Creates index already exists error
   * @param indexName - Name of the index that already exists
   */
  constructor(indexName: string);
}

Indices in Same App Error:

/**
 * Error when operation requires indices in different applications
 */
class IndicesInSameAppError extends AlgoliaError {
  /**
   * Creates same application error
   */
  constructor();
}

Usage Examples

Basic Error Handling:

import { 
  createTransporter, 
  ApiError, 
  RetryError, 
  DeserializationError 
} from "@algolia/client-common";

try {
  const response = await transporter.request({
    method: 'GET',
    path: '/1/indexes/my-index',
    queryParameters: {},
    headers: {}
  });
} catch (error) {
  if (error instanceof ApiError) {
    console.error(`API Error (${error.status}): ${error.message}`);
    
    // Access stack trace for detailed debugging
    error.stackTrace.forEach((frame, index) => {
      console.log(`Attempt ${index + 1}:`, {
        host: frame.host.url,
        status: frame.response.status,
        triesLeft: frame.triesLeft
      });
    });
    
  } else if (error instanceof RetryError) {
    console.error('All hosts unreachable:', error.message);
    
    // Show which hosts were attempted
    error.stackTrace.forEach(frame => {
      console.log(`Tried ${frame.host.url}: ${frame.response.status}`);
    });
    
  } else if (error instanceof DeserializationError) {
    console.error('Invalid JSON response:', error.message);
    console.log('Raw response:', error.response.content);
    
  } else {
    console.error('Unexpected error:', error);
  }
}

Detailed Error Information:

import { DetailedApiError, DetailedError } from "@algolia/client-common";

try {
  // API operation that might fail with detailed error
  await apiOperation();
} catch (error) {
  if (error instanceof DetailedApiError) {
    console.error(`Detailed API Error: ${error.message}`);
    console.error(`Status: ${error.status}`);
    console.error(`Error Code: ${error.error.code}`);
    
    if (error.error.details) {
      console.error('Error Details:');
      error.error.details.forEach(detail => {
        if ('message' in detail) {
          console.error(`- ${detail.label}: ${detail.message}`);
        } else {
          console.error(`- ${detail.type} (${detail.id}): ${detail.name}`);
        }
      });
    }
  }
}

Index Operations Error Handling:

import { 
  IndexNotFoundError, 
  IndexAlreadyExistsError,
  IndicesInSameAppError 
} from "@algolia/client-common";

// Creating index
try {
  await createIndex('my-new-index');
} catch (error) {
  if (error instanceof IndexAlreadyExistsError) {
    console.log('Index already exists, continuing...');
  } else {
    throw error; // Re-throw other errors
  }
}

// Searching index
try {
  const results = await searchIndex('non-existent-index', query);
} catch (error) {
  if (error instanceof IndexNotFoundError) {
    console.error('Index does not exist. Please create it first.');
    return { hits: [], nbHits: 0 };
  } else {
    throw error;
  }
}

// Cross-index operations
try {
  await copyIndex('source-index', 'target-index');
} catch (error) {
  if (error instanceof IndicesInSameAppError) {
    console.error('Use operationIndex for same-app operations');
  } else {
    throw error;
  }
}

Error Analysis and Debugging

Stack Trace Analysis:

import { ErrorWithStackTrace, StackFrame } from "@algolia/client-common";

function analyzeError(error: ErrorWithStackTrace): void {
  console.log(`Error: ${error.message}`);
  console.log(`Attempts made: ${error.stackTrace.length}`);
  
  const hostAttempts = new Map<string, number>();
  const statusCodes = new Map<number, number>();
  
  error.stackTrace.forEach((frame: StackFrame) => {
    // Count attempts per host
    const hostUrl = frame.host.url;
    hostAttempts.set(hostUrl, (hostAttempts.get(hostUrl) || 0) + 1);
    
    // Count status codes
    const status = frame.response.status;
    statusCodes.set(status, (statusCodes.get(status) || 0) + 1);
  });
  
  console.log('Host attempts:', Object.fromEntries(hostAttempts));
  console.log('Status code distribution:', Object.fromEntries(statusCodes));
  
  // Find timeouts
  const timeouts = error.stackTrace.filter(frame => frame.response.isTimedOut);
  console.log(`Timeouts: ${timeouts.length}/${error.stackTrace.length}`);
}

Error Recovery Strategies:

import { ApiError, RetryError } from "@algolia/client-common";

async function robustApiCall<T>(operation: () => Promise<T>): Promise<T> {
  const maxRetries = 3;
  let lastError: Error;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;
      
      if (error instanceof ApiError) {
        // Don't retry client errors (4xx)
        if (error.status >= 400 && error.status < 500) {
          throw error;
        }
        
        // Retry server errors (5xx)
        if (attempt < maxRetries) {
          const delay = Math.pow(2, attempt - 1) * 1000; // Exponential backoff
          console.log(`API error ${error.status}, retrying in ${delay}ms...`);
          await new Promise(resolve => setTimeout(resolve, delay));
          continue;
        }
      } else if (error instanceof RetryError) {
        // Transport layer already exhausted retries
        throw error;
      }
      
      // Other errors - retry with delay
      if (attempt < maxRetries) {
        console.log(`Attempt ${attempt} failed, retrying...`);
        await new Promise(resolve => setTimeout(resolve, 1000));
      }
    }
  }
  
  throw lastError;
}

Error Reporting:

import { AlgoliaError, ErrorWithStackTrace } from "@algolia/client-common";

interface ErrorReport {
  timestamp: string;
  errorType: string;
  message: string;
  statusCode?: number;
  stackTrace?: Array<{
    host: string;
    status: number;
    isTimedOut: boolean;
    triesLeft: number;
  }>;
  userAgent?: string;
  requestDetails?: any;
}

function createErrorReport(error: Error, context?: any): ErrorReport {
  const report: ErrorReport = {
    timestamp: new Date().toISOString(),
    errorType: error.constructor.name,
    message: error.message
  };
  
  if (error instanceof ErrorWithStackTrace) {
    report.stackTrace = error.stackTrace.map(frame => ({
      host: frame.host.url,
      status: frame.response.status,
      isTimedOut: frame.response.isTimedOut,
      triesLeft: frame.triesLeft
    }));
  }
  
  if (error instanceof ApiError) {
    report.statusCode = error.status;
  }
  
  if (context) {
    report.requestDetails = context;
    report.userAgent = context.userAgent;
  }
  
  return report;
}

// Usage
try {
  await apiOperation();
} catch (error) {
  if (error instanceof AlgoliaError) {
    const report = createErrorReport(error, { 
      operation: 'search',
      indexName: 'products',
      userAgent: 'MyApp/1.0.0'
    });
    
    // Send to monitoring service
    await sendErrorReport(report);
  }
  
  throw error;
}

Best Practices

Error Handling Strategy:

  1. Catch Specific Errors: Use instanceof checks for targeted error handling
  2. Preserve Stack Traces: Don't lose valuable debugging information
  3. Log Appropriately: Use different log levels based on error severity
  4. Fail Fast: Don't retry client errors (4xx status codes)
  5. Implement Backoff: Use exponential backoff for retryable errors

Error Prevention:

// Validate inputs before making requests
function validateSearchParams(params: any): void {
  if (!params.indexName) {
    throw new Error('Index name is required');
  }
  
  if (params.query && typeof params.query !== 'string') {
    throw new Error('Query must be a string');
  }
}

// Use proper error boundaries in applications
try {
  validateSearchParams(searchParams);
  const results = await performSearch(searchParams);
  return results;
} catch (error) {
  // Handle validation errors separately from API errors
  if (error instanceof AlgoliaError) {
    // API-related error handling
  } else {
    // Validation or other errors
  }
}

Monitoring Integration:

// Integration with error monitoring services
import { AlgoliaError, ApiError, RetryError } from "@algolia/client-common";

function reportToMonitoring(error: Error, context: any): void {
  const errorData = {
    name: error.constructor.name,
    message: error.message,
    context
  };
  
  if (error instanceof ApiError) {
    errorData.tags = {
      status_code: error.status,
      error_type: 'api_error'
    };
  } else if (error instanceof RetryError) {
    errorData.tags = {
      error_type: 'connectivity_error',
      hosts_attempted: error.stackTrace.length
    };
  }
  
  // Send to your monitoring service (Sentry, DataDog, etc.)
  monitoringService.captureException(error, errorData);
}