Comprehensive error system with specific error types for different failure scenarios, stack trace management, and detailed error information for debugging and monitoring.
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);
}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 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();
}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;
}
}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;
}Error Handling Strategy:
instanceof checks for targeted error handlingError 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);
}