> ## Documentation Index
> Fetch the complete documentation index at: https://docs.joinrefine.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Handle errors gracefully with typed error classes and retry strategies

## Overview

The SDK provides typed error classes for different failure scenarios. Some errors are retryable (network issues, rate limits), while others require code changes (validation, auth).

## Error Types

| Error Class             | Status Code   | Retryable | Cause                      |
| ----------------------- | ------------- | --------- | -------------------------- |
| `RefineValidationError` | 400           | No        | Invalid request parameters |
| `RefineAuthError`       | 401           | No        | Invalid or missing API key |
| `RefineForbiddenError`  | 403           | No        | Insufficient permissions   |
| `RefineNotFoundError`   | 404           | No        | Resource doesn't exist     |
| `RefineRateLimitError`  | 429           | Yes       | Too many requests          |
| `RefineTimeoutError`    | 408, 504      | Yes       | Request timed out          |
| `RefineServerError`     | 500, 502, 503 | Yes       | Server-side issue          |
| `RefineNetworkError`    | -             | Yes       | Network connectivity issue |

## Basic Error Handling

```typescript theme={null}
import { 
  Refine,
  RefineValidationError,
  RefineAuthError,
  RefineNotFoundError,
  RefineRateLimitError,
  RefineServerError,
  RefineNetworkError
} from '@refine-ai/sdk';

const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789'
});

try {
  const results = await refine.search.text({
    query: 'summer dress',
    topK: 24
  });
} catch (error) {
  if (error instanceof RefineValidationError) {
    // Bad request - fix the parameters
    console.error('Invalid parameters:', error.message);
  } else if (error instanceof RefineAuthError) {
    // Auth issue - check API key
    console.error('Authentication failed:', error.message);
  } else if (error instanceof RefineNotFoundError) {
    // Resource not found
    console.error('Not found:', error.message);
  } else if (error instanceof RefineRateLimitError) {
    // Rate limited - wait and retry
    console.error(`Rate limited. Retry after ${error.retryAfter}ms`);
  } else if (error instanceof RefineServerError) {
    // Server error - retry with backoff
    console.error('Server error:', error.message);
  } else if (error instanceof RefineNetworkError) {
    // Network issue - check connectivity
    console.error('Network error:', error.message);
  } else {
    // Unknown error
    throw error;
  }
}
```

## Error Properties

All Refine errors extend `RefineError` and include:

```typescript theme={null}
interface RefineError extends Error {
  name: string;          // Error class name
  message: string;       // Human-readable message
  statusCode?: number;   // HTTP status code
  retryable: boolean;    // Whether retry might succeed
  retryAfter?: number;   // Suggested retry delay (ms)
  requestId?: string;    // Request ID for support
}
```

## Retry Strategies

For retryable errors, implement exponential backoff:

```typescript theme={null}
async function searchWithRetry(
  query: string,
  maxRetries: number = 3
): Promise<SearchResponse> {
  let lastError: Error;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await refine.search.text({ query, topK: 24 });
    } catch (error) {
      lastError = error;
      
      if (error instanceof RefineRateLimitError) {
        // Use server-provided retry delay
        await sleep(error.retryAfter || 1000);
      } else if (
        error instanceof RefineServerError ||
        error instanceof RefineTimeoutError ||
        error instanceof RefineNetworkError
      ) {
        // Exponential backoff
        await sleep(Math.pow(2, attempt) * 1000);
      } else {
        // Non-retryable error
        throw error;
      }
    }
  }
  
  throw lastError;
}

function sleep(ms: number): Promise<void> {
  return new Promise(resolve => setTimeout(resolve, ms));
}
```

## Global Error Handler

Set a global error handler in configuration:

```typescript theme={null}
const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  onError: (error) => {
    // Log to error tracking service
    errorTracker.capture(error, {
      requestId: error.requestId,
      statusCode: error.statusCode
    });
    
    // Show user-friendly message
    if (error.retryable) {
      showNotification('Temporary issue. Please try again.');
    } else {
      showNotification('Something went wrong. Please contact support.');
    }
  }
});
```

## Error Handling by Feature

### Search

```typescript theme={null}
async function performSearch(query: string) {
  try {
    return await refine.search.text({ query, topK: 24 });
  } catch (error) {
    if (error instanceof RefineValidationError) {
      // Query too short, invalid filters, etc.
      return { results: [], error: 'Invalid search query' };
    }
    if (error.retryable) {
      // Show loading state and retry
      return await searchWithRetry(query);
    }
    // Non-retryable error
    return { results: [], error: 'Search unavailable' };
  }
}
```

### Recommendations

```typescript theme={null}
async function getSimilarItems(productId: string) {
  try {
    return await refine.recs.similarItems({
      anchorId: productId,
      topK: 8
    });
  } catch (error) {
    if (error instanceof RefineNotFoundError) {
      // Product not in catalog - fall back to popular items
      return await refine.recs.forVisitor({
        configId: 'popular',
        topK: 8
      });
    }
    if (error.retryable) {
      // Retry once
      await sleep(1000);
      return await refine.recs.similarItems({
        anchorId: productId,
        topK: 8
      });
    }
    // Return empty recommendations
    return { results: [] };
  }
}
```

### Event Tracking

Event tracking is designed to be fire-and-forget, but you can handle errors:

```typescript theme={null}
try {
  refine.events.trackPurchase({
    orderId: 'order_123',
    value: 99.99,
    currency: 'USD',
    items: [{ itemId: 'sku_001', quantity: 1, unitPrice: 99.99 }]
  });
} catch (error) {
  // Events are queued, so errors here are rare
  console.error('Failed to queue event:', error);
}

// Flush errors
try {
  await refine.events.flush();
} catch (error) {
  if (error instanceof RefineNetworkError) {
    // Events will be retried automatically
    console.warn('Events queued for retry');
  }
}
```

## User-Facing Error Messages

Map errors to user-friendly messages:

```typescript theme={null}
function getUserMessage(error: RefineError): string {
  if (error instanceof RefineValidationError) {
    return 'Please check your search query and try again.';
  }
  if (error instanceof RefineRateLimitError) {
    return 'Too many requests. Please wait a moment.';
  }
  if (error instanceof RefineNetworkError) {
    return 'Connection issue. Check your internet and try again.';
  }
  if (error.retryable) {
    return 'Temporary issue. Please try again.';
  }
  return 'Something went wrong. Please try again later.';
}
```

## Debugging Errors

Enable debug mode for detailed error information:

```typescript theme={null}
const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  debug: true
});

// Errors will include:
// - Full request/response details
// - Request ID for support
// - Stack trace
```

## Error Monitoring Integration

Integrate with error monitoring services:

```typescript theme={null}
import * as Sentry from '@sentry/browser';

const refine = new Refine({
  apiKey: process.env.REFINE_API_KEY,
  organizationId: 'org_abc123',
  catalogId: 'cat_xyz789',
  onError: (error) => {
    Sentry.captureException(error, {
      tags: {
        refine_error: error.name,
        retryable: error.retryable,
        status_code: error.statusCode
      },
      extra: {
        request_id: error.requestId
      }
    });
  }
});
```

## Handling Specific Scenarios

### Rate Limiting

```typescript theme={null}
import { RefineRateLimitError } from '@refine-ai/sdk';

async function handleRateLimit<T>(
  operation: () => Promise<T>
): Promise<T> {
  try {
    return await operation();
  } catch (error) {
    if (error instanceof RefineRateLimitError) {
      // Show user feedback
      showNotification(`Please wait ${Math.ceil(error.retryAfter / 1000)} seconds`);
      
      // Wait and retry once
      await sleep(error.retryAfter);
      return await operation();
    }
    throw error;
  }
}

// Usage
const results = await handleRateLimit(() => 
  refine.search.text({ query: 'shoes', topK: 24 })
);
```

### Network Offline

```typescript theme={null}
import { RefineNetworkError } from '@refine-ai/sdk';

async function searchWithOfflineSupport(query: string) {
  try {
    return await refine.search.text({ query, topK: 24 });
  } catch (error) {
    if (error instanceof RefineNetworkError) {
      // Check if actually offline
      if (!navigator.onLine) {
        showNotification('You appear to be offline');
        return getCachedResults(query);
      }
      // Online but network error - retry
      await sleep(2000);
      return await refine.search.text({ query, topK: 24 });
    }
    throw error;
  }
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="SDK Configuration" icon="gear" href="/sdk/configuration">
    Configure error handling globally
  </Card>

  <Card title="Debug Plugin" icon="bug" href="/sdk/plugins/debug-plugin">
    Debug errors in development
  </Card>
</CardGroup>
