lib/ruby_llm/error.rb
# frozen_string_literal: true module RubyLLM # Custom error class that wraps API errors from different providers # into a consistent format with helpful error messages. # # Example: # begin # chat.ask "What's 2+2?" # rescue RubyLLM::Error => e # puts "Couldn't chat with AI: #{e.message}" # end class Error < StandardError attr_reader :response def initialize(response = nil, message = nil) @response = response super(message || response&.body) end end class ModelNotFoundError < StandardError; end class InvalidRoleError < StandardError; end class UnsupportedFunctionsError < StandardError; end class UnauthorizedError < Error; end class PaymentRequiredError < Error; end class ServiceUnavailableError < Error; end class BadRequestError < Error; end class RateLimitError < Error; end class ServerError < Error; end # Faraday middleware that maps provider-specific API errors to RubyLLM errors. # Uses provider's parse_error method to extract meaningful error messages. class ErrorMiddleware < Faraday::Middleware def initialize(app, provider:) super(app) @provider = provider end def call(env) @app.call(env).on_complete do |response| self.class.parse_error(provider: @provider, response: response) end end class << self def parse_error(provider:, response:) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/AbcSize,Metrics/PerceivedComplexity message = provider&.parse_error(response) case response.status when 200..399 message when 400 raise BadRequestError.new(response, message || 'Invalid request - please check your input') when 401 raise UnauthorizedError.new(response, message || 'Invalid API key - check your credentials') when 402 raise PaymentRequiredError.new(response, message || 'Payment required - please top up your account') when 429 raise RateLimitError.new(response, message || 'Rate limit exceeded - please wait a moment') when 500 raise ServerError.new(response, message || 'API server error - please try again') when 503 raise ServiceUnavailableError.new(response, message || 'API server unavailable - please try again later') else raise Error.new(response, message || 'An unknown error occurred') end end end end end Faraday::Middleware.register_middleware(llm_errors: RubyLLM::ErrorMiddleware)