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

# Error Handling

> Handle SDK errors gracefully

## Overview

The RunAnywhere SDK provides structured error handling through `SDKError` with specific error codes and categories. This guide covers error types, handling patterns, and recovery strategies.

## SDKError Structure

```typescript theme={null}
interface SDKError extends Error {
  /** Unique error code */
  code: SDKErrorCode

  /** Error category */
  category: ErrorCategory

  /** Original error (if wrapped) */
  underlyingError?: Error

  /** Additional context */
  context?: ErrorContext

  /** Suggested recovery action */
  recoverySuggestion?: string
}
```

## Checking for SDK Errors

```typescript theme={null}
import { isSDKError, SDKError, SDKErrorCode } from '@runanywhere/core'

try {
  await RunAnywhere.generate('Hello')
} catch (error) {
  if (isSDKError(error)) {
    // Handle SDK-specific error
    console.log('Code:', error.code)
    console.log('Category:', error.category)
    console.log('Message:', error.message)
    console.log('Recovery:', error.recoverySuggestion)
  } else {
    // Handle generic error
    console.error('Unexpected error:', error)
  }
}
```

## Error Codes

### General Errors

| Code                       | Description              | Recovery                                |
| -------------------------- | ------------------------ | --------------------------------------- |
| `notInitialized`           | SDK not initialized      | Call `RunAnywhere.initialize()`         |
| `alreadyInitialized`       | SDK already initialized  | Use existing instance or call `reset()` |
| `invalidInput`             | Invalid input parameters | Check input values                      |
| `nativeModuleNotAvailable` | Native module not linked | Rebuild app, check pod install          |

### Model Errors

| Code                  | Description           | Recovery                             |
| --------------------- | --------------------- | ------------------------------------ |
| `modelNotFound`       | Model not in registry | Add model with `LlamaCPP.addModel()` |
| `modelLoadFailed`     | Failed to load model  | Check model path, format, memory     |
| `modelNotLoaded`      | No model loaded       | Call `loadModel()` first             |
| `modelDownloadFailed` | Download failed       | Check network, retry                 |

### Generation Errors

| Code                  | Description              | Recovery                                |
| --------------------- | ------------------------ | --------------------------------------- |
| `generationFailed`    | Text generation failed   | Check model, reduce tokens              |
| `generationCancelled` | Generation was cancelled | Expected if `cancelGeneration()` called |

### Voice Errors

| Code               | Description           | Recovery                  |
| ------------------ | --------------------- | ------------------------- |
| `sttFailed`        | Transcription failed  | Check audio format, model |
| `ttsFailed`        | Synthesis failed      | Check TTS model, text     |
| `vadFailed`        | VAD failed            | Check VAD configuration   |
| `voiceAgentFailed` | Voice pipeline failed | Check all models loaded   |

### Resource Errors

| Code                  | Description           | Recovery                         |
| --------------------- | --------------------- | -------------------------------- |
| `insufficientStorage` | Not enough disk space | Free storage, delete models      |
| `insufficientMemory`  | Not enough RAM        | Unload models, use smaller model |
| `downloadFailed`      | Download failed       | Check network, storage           |
| `downloadCancelled`   | Download cancelled    | Expected if cancelled by user    |

### Network/Auth Errors

| Code                   | Description           | Recovery           |
| ---------------------- | --------------------- | ------------------ |
| `networkUnavailable`   | No network connection | Check connectivity |
| `authenticationFailed` | Invalid API key       | Check API key      |
| `permissionDenied`     | Missing permission    | Request permission |

## Error Categories

```typescript theme={null}
enum ErrorCategory {
  General = 'general',
  LLM = 'llm',
  STT = 'stt',
  TTS = 'tts',
  VAD = 'vad',
  VoiceAgent = 'voiceAgent',
  Download = 'download',
  Network = 'network',
  Authentication = 'authentication',
  Storage = 'storage',
  Memory = 'memory',
}
```

## Handling Patterns

### Comprehensive Error Handler

```typescript theme={null}
import { isSDKError, SDKError, SDKErrorCode, ErrorCategory } from '@runanywhere/core'

async function handleSDKOperation<T>(
  operation: () => Promise<T>,
  options?: {
    onRetry?: () => void
    maxRetries?: number
  }
): Promise<T> {
  const maxRetries = options?.maxRetries ?? 1
  let lastError: Error | null = null

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await operation()
    } catch (error) {
      lastError = error as Error

      if (!isSDKError(error)) {
        throw error // Non-SDK error, don't retry
      }

      // Handle specific errors
      switch (error.code) {
        // Retryable errors
        case SDKErrorCode.networkUnavailable:
        case SDKErrorCode.downloadFailed:
          if (attempt < maxRetries) {
            options?.onRetry?.()
            await delay(1000 * (attempt + 1)) // Exponential backoff
            continue
          }
          break

        // Non-retryable errors
        case SDKErrorCode.notInitialized:
        case SDKErrorCode.modelNotFound:
        case SDKErrorCode.invalidInput:
        case SDKErrorCode.insufficientStorage:
          throw error

        // Memory errors - try recovery
        case SDKErrorCode.insufficientMemory:
          await RunAnywhere.unloadModel()
          if (attempt < maxRetries) {
            continue
          }
          break
      }

      throw error
    }
  }

  throw lastError
}

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

### Category-Based Handling

```typescript theme={null}
function handleError(error: SDKError): string {
  switch (error.category) {
    case ErrorCategory.LLM:
      return handleLLMError(error)
    case ErrorCategory.STT:
      return handleSTTError(error)
    case ErrorCategory.TTS:
      return handleTTSError(error)
    case ErrorCategory.Network:
      return 'Please check your internet connection.'
    case ErrorCategory.Storage:
      return 'Not enough storage space. Please free up some space.'
    case ErrorCategory.Memory:
      return 'Not enough memory. Try closing other apps.'
    default:
      return error.recoverySuggestion || error.message
  }
}

function handleLLMError(error: SDKError): string {
  switch (error.code) {
    case SDKErrorCode.modelNotLoaded:
      return 'Please wait for the AI model to load.'
    case SDKErrorCode.generationFailed:
      return 'Failed to generate response. Please try again.'
    case SDKErrorCode.generationCancelled:
      return 'Generation was cancelled.'
    default:
      return 'An error occurred with the AI model.'
  }
}
```

### React Hook for Error Handling

```typescript useSDKError.ts theme={null}
import { useState, useCallback } from 'react'
import { isSDKError, SDKError, SDKErrorCode } from '@runanywhere/core'

interface ErrorState {
  error: SDKError | Error | null
  userMessage: string | null
  canRetry: boolean
}

export function useSDKError() {
  const [errorState, setErrorState] = useState<ErrorState>({
    error: null,
    userMessage: null,
    canRetry: false,
  })

  const handleError = useCallback((error: unknown) => {
    if (isSDKError(error)) {
      const canRetry = [
        SDKErrorCode.networkUnavailable,
        SDKErrorCode.downloadFailed,
        SDKErrorCode.generationFailed,
      ].includes(error.code)

      setErrorState({
        error,
        userMessage: getErrorMessage(error),
        canRetry,
      })
    } else {
      setErrorState({
        error: error as Error,
        userMessage: 'An unexpected error occurred.',
        canRetry: false,
      })
    }
  }, [])

  const clearError = useCallback(() => {
    setErrorState({ error: null, userMessage: null, canRetry: false })
  }, [])

  return { ...errorState, handleError, clearError }
}

function getErrorMessage(error: SDKError): string {
  // Return user-friendly messages based on error code
  switch (error.code) {
    case SDKErrorCode.notInitialized:
      return 'The app is still loading. Please wait.'
    case SDKErrorCode.modelNotLoaded:
      return 'The AI model is not ready yet.'
    case SDKErrorCode.networkUnavailable:
      return 'No internet connection.'
    case SDKErrorCode.insufficientMemory:
      return 'Not enough memory. Try closing other apps.'
    case SDKErrorCode.insufficientStorage:
      return 'Not enough storage space.'
    default:
      return error.recoverySuggestion || error.message
  }
}
```

### Error Display Component

```tsx ErrorDisplay.tsx theme={null}
import React from 'react'
import { View, Text, Button, StyleSheet } from 'react-native'
import { SDKError } from '@runanywhere/core'

interface Props {
  error: SDKError | Error
  message: string
  canRetry: boolean
  onRetry?: () => void
  onDismiss?: () => void
}

export function ErrorDisplay({ error, message, canRetry, onRetry, onDismiss }: Props) {
  return (
    <View style={styles.container}>
      <Text style={styles.icon}>⚠️</Text>
      <Text style={styles.message}>{message}</Text>

      <View style={styles.buttons}>
        {canRetry && onRetry && <Button title="Retry" onPress={onRetry} />}
        {onDismiss && <Button title="Dismiss" onPress={onDismiss} color="#666" />}
      </View>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#fff3cd',
    borderRadius: 8,
    alignItems: 'center',
  },
  icon: { fontSize: 32, marginBottom: 8 },
  message: { fontSize: 16, textAlign: 'center', marginBottom: 16 },
  buttons: { flexDirection: 'row', gap: 8 },
})
```

## Creating Custom Errors

```typescript theme={null}
import {
  notInitializedError,
  modelNotFoundError,
  modelLoadError,
  generationError,
  networkError,
} from '@runanywhere/core'

// Use factory functions
throw notInitializedError()
throw modelNotFoundError('my-model-id')
throw generationError('Context window exceeded')
```

## Logging Errors

```typescript theme={null}
import { SDKLogger } from '@runanywhere/core'

const logger = new SDKLogger('MyApp')

try {
  await RunAnywhere.generate(prompt)
} catch (error) {
  if (isSDKError(error)) {
    logger.error('SDK Error', error, {
      code: error.code,
      category: error.category,
    })
  } else {
    logger.error('Unexpected error', error as Error)
  }
}
```

## Related

<CardGroup cols={2}>
  <Card title="Configuration" icon="gear" href="/react-native/configuration">
    SDK configuration
  </Card>

  <Card title="Best Practices" icon="star" href="/react-native/best-practices">
    Optimization tips
  </Card>
</CardGroup>
