Skip to content

Error Handling

Amayyas edited this page Dec 5, 2025 · 1 revision

Error Handling

Flutter AI SDK provides comprehensive error handling with specific error types for different failure scenarios.

Error Hierarchy

AIError (base)
├── AIAuthenticationError    - Invalid/expired API key
├── AIRateLimitError        - Rate limit exceeded
├── AIContextLengthError    - Context too long
├── AIContentFilterError    - Content was filtered
├── AIInvalidRequestError   - Malformed request
├── AIModelNotFoundError    - Model doesn't exist
├── AINetworkError          - Network/connectivity issues
├── AIServerError           - Provider server error
└── AITimeoutError          - Request timed out

Basic Error Handling

try {
  final response = await ai.chat('Hello');
  print(response.text);
} on AIError catch (e) {
  print('AI Error: ${e.message}');
  print('Code: ${e.code}');
}

Specific Error Types

AIAuthenticationError

Thrown when the API key is invalid or expired.

try {
  await ai.chat('Hello');
} on AIAuthenticationError catch (e) {
  print('Authentication failed: ${e.message}');
  // Prompt user to update API key
}

AIRateLimitError

Thrown when you've exceeded the rate limit.

try {
  await ai.chat('Hello');
} on AIRateLimitError catch (e) {
  print('Rate limited: ${e.message}');
  
  if (e.retryAfter != null) {
    print('Retry after: ${e.retryAfter!.inSeconds} seconds');
    await Future.delayed(e.retryAfter!);
    // Retry the request
  }
}

Properties:

  • retryAfter - Duration to wait before retrying

AIContextLengthError

Thrown when the context (conversation history) is too long.

try {
  await ai.chat('Very long message...');
} on AIContextLengthError catch (e) {
  print('Context too long: ${e.message}');
  print('Max tokens: ${e.maxTokens}');
  print('Requested: ${e.requestedTokens}');
  
  // Clear context and retry
  ai.clearContext();
}

Properties:

  • maxTokens - Maximum allowed tokens
  • requestedTokens - Tokens that were requested

AIContentFilterError

Thrown when content is blocked by safety filters.

try {
  await ai.chat(message);
} on AIContentFilterError catch (e) {
  print('Content filtered: ${e.message}');
  print('Categories: ${e.categories}');
}

Properties:

  • categories - List of triggered filter categories

AINetworkError

Thrown for network-related issues.

try {
  await ai.chat('Hello');
} on AINetworkError catch (e) {
  print('Network error: ${e.message}');
  
  if (e.isTimeout) {
    print('Request timed out');
  }
}

Properties:

  • isTimeout - Whether the error was a timeout
  • statusCode - HTTP status code (if available)

AIServerError

Thrown when the provider's server has issues.

try {
  await ai.chat('Hello');
} on AIServerError catch (e) {
  print('Server error: ${e.message}');
  print('Status: ${e.statusCode}');
  // Usually 500, 502, 503
}

AIInvalidRequestError

Thrown for malformed requests.

try {
  await ai.chat('Hello');
} on AIInvalidRequestError catch (e) {
  print('Invalid request: ${e.message}');
  // Check parameters
}

AIModelNotFoundError

Thrown when the specified model doesn't exist.

try {
  await ai.chat('Hello');
} on AIModelNotFoundError catch (e) {
  print('Model not found: ${e.message}');
  print('Model: ${e.model}');
  // Use a different model
}

Complete Error Handling Pattern

Future<String?> safeChatRequest(FlutterAI ai, String message) async {
  try {
    final response = await ai.chat(message);
    return response.text;
    
  } on AIAuthenticationError catch (e) {
    // Handle auth errors
    print('Please check your API key');
    return null;
    
  } on AIRateLimitError catch (e) {
    // Handle rate limiting with retry
    if (e.retryAfter != null) {
      await Future.delayed(e.retryAfter!);
      return safeChatRequest(ai, message); // Retry
    }
    return null;
    
  } on AIContextLengthError catch (e) {
    // Clear context and retry
    ai.clearContext();
    return safeChatRequest(ai, message);
    
  } on AIContentFilterError catch (e) {
    // Content was filtered
    print('Your message was filtered');
    return null;
    
  } on AINetworkError catch (e) {
    // Network issues
    print('Please check your internet connection');
    return null;
    
  } on AIServerError catch (e) {
    // Provider issues
    print('Service temporarily unavailable');
    return null;
    
  } on AIError catch (e) {
    // Catch-all for other AI errors
    print('Error: ${e.message}');
    return null;
    
  } catch (e) {
    // Unexpected errors
    print('Unexpected error: $e');
    return null;
  }
}

Error Properties

All AIError subclasses have:

Property Type Description
message String Human-readable error message
code String? Error code from provider
details Map<String, dynamic>? Additional error details
stackTrace StackTrace? Stack trace for debugging

Retry Logic

Implement automatic retry for transient errors:

Future<AIResponse> chatWithRetry(
  FlutterAI ai,
  String message, {
  int maxRetries = 3,
}) async {
  for (var attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await ai.chat(message);
      
    } on AIRateLimitError catch (e) {
      if (attempt == maxRetries) rethrow;
      
      final delay = e.retryAfter ?? Duration(seconds: attempt * 2);
      await Future.delayed(delay);
      
    } on AINetworkError catch (e) {
      if (attempt == maxRetries) rethrow;
      if (e.isTimeout) {
        await Future.delayed(Duration(seconds: attempt));
      } else {
        rethrow;
      }
      
    } on AIServerError catch (e) {
      if (attempt == maxRetries) rethrow;
      await Future.delayed(Duration(seconds: attempt * 2));
    }
  }
  
  throw Exception('Max retries exceeded');
}

Streaming Error Handling

Handle errors in streaming responses:

try {
  await for (final chunk in ai.streamChat(message)) {
    if (chunk.isError) {
      throw chunk.error!;
    }
    
    if (chunk.isDelta) {
      print(chunk.delta);
    }
  }
} on AIError catch (e) {
  print('Stream error: ${e.message}');
}

Error Logging

Implement comprehensive error logging:

void logAIError(AIError error) {
  final log = StringBuffer()
    ..writeln('=== AI Error ===')
    ..writeln('Type: ${error.runtimeType}')
    ..writeln('Message: ${error.message}')
    ..writeln('Code: ${error.code}');
  
  if (error.details != null) {
    log.writeln('Details: ${error.details}');
  }
  
  if (error is AIRateLimitError && error.retryAfter != null) {
    log.writeln('Retry After: ${error.retryAfter!.inSeconds}s');
  }
  
  if (error is AIContextLengthError) {
    log.writeln('Max Tokens: ${error.maxTokens}');
    log.writeln('Requested: ${error.requestedTokens}');
  }
  
  print(log);
}

Flutter UI Integration

Show user-friendly error messages:

String getUserFriendlyMessage(AIError error) {
  return switch (error) {
    AIAuthenticationError() => 
      'Unable to connect. Please check your API key.',
    AIRateLimitError() => 
      'Too many requests. Please wait a moment.',
    AIContextLengthError() => 
      'Conversation too long. Starting fresh.',
    AIContentFilterError() => 
      'Your message couldn\'t be processed.',
    AINetworkError() => 
      'Connection issue. Check your internet.',
    AIServerError() => 
      'Service temporarily unavailable.',
    _ => 'Something went wrong. Please try again.',
  };
}

// In your widget
try {
  final response = await ai.chat(message);
  setState(() => _response = response.text);
} on AIError catch (e) {
  ScaffoldMessenger.of(context).showSnackBar(
    SnackBar(content: Text(getUserFriendlyMessage(e))),
  );
}

Related

Clone this wiki locally