Skip to main content

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

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

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

CodeDescriptionRecovery
notInitializedSDK not initializedCall RunAnywhere.initialize()
alreadyInitializedSDK already initializedUse existing instance or call reset()
invalidInputInvalid input parametersCheck input values
nativeModuleNotAvailableNative module not linkedRebuild app, check pod install

Model Errors

CodeDescriptionRecovery
modelNotFoundModel not in registryAdd model with LlamaCPP.addModel()
modelLoadFailedFailed to load modelCheck model path, format, memory
modelNotLoadedNo model loadedCall loadModel() first
modelDownloadFailedDownload failedCheck network, retry

Generation Errors

CodeDescriptionRecovery
generationFailedText generation failedCheck model, reduce tokens
generationCancelledGeneration was cancelledExpected if cancelGeneration() called

Voice Errors

CodeDescriptionRecovery
sttFailedTranscription failedCheck audio format, model
ttsFailedSynthesis failedCheck TTS model, text
vadFailedVAD failedCheck VAD configuration
voiceAgentFailedVoice pipeline failedCheck all models loaded

Resource Errors

CodeDescriptionRecovery
insufficientStorageNot enough disk spaceFree storage, delete models
insufficientMemoryNot enough RAMUnload models, use smaller model
downloadFailedDownload failedCheck network, storage
downloadCancelledDownload cancelledExpected if cancelled by user

Network/Auth Errors

CodeDescriptionRecovery
networkUnavailableNo network connectionCheck connectivity
authenticationFailedInvalid API keyCheck API key
permissionDeniedMissing permissionRequest permission

Error Categories

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

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

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

useSDKError.ts
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

ErrorDisplay.tsx
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

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

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)
  }
}