we-promise/sure · error · StandardError

No LLM provider configured that supports model '#

Error message

No LLM provider configured that supports model '#{requested_model}'.\n\nAvailable providers:\n#{provider_details}\n\nPlease either:\n  1. Use a supported model from the list above, or\n  2. Configure a provider that supports '#{requested_model}' in settings.

What it means

Assistant::Builtin#respond_to resolves which LLM provider to use for the chat's requested model via get_model_provider(message.ai_model); if no configured provider (OpenAI / Anthropic settings) supports that model, it builds a diagnostic message — "No LLM provider configured that supports model 'X'" plus the list of available providers with their models — and raises StandardError. The message is intentionally actionable: it tells the user to either pick a supported model or configure a provider in settings.

Solutions

  1. In the chat, switch the model selector to one listed in the error's "Available providers" section and resend
  2. Or complete the provider config: Settings > Self-Hosting — add the API key (and base URL/model pair for custom endpoints) for a provider that serves the requested model
  3. For custom/self-hosted model gateways, ensure the provider's configured model list actually contains the exact string being requested (watch versions/aliases: 'gpt-4o' vs 'gpt-4o-2024-08-06')
  4. For stale old chats, bulk-update AssistantMessage/chat ai_model to a currently supported model or delete the chats

Example fix

# before
message = chat.messages.create!(content: "hi", ai_model: "claude-3-opus-20230101")
Assistant::Builtin.new(chat).respond_to(message)
# => StandardError: No LLM provider configured that supports model 'claude-3-opus-20230101'. ...

# after: use a model from the configured provider's list
supported = Assistant::Builtin.new(chat).send(:get_model_provider, "gpt-4o")&.configured_models rescue []
message = chat.messages.create!(content: "hi", ai_model: "gpt-4o") # matches provider config
Assistant::Builtin.new(chat).respond_to(message)
Defensive patterns

Strategy: validation

Validate before calling

# Before sending, verify the requested model is served
chat = Chat.find(chat_id)
provider = Assistant::Builtin.new(chat).send(:get_model_provider, chat.assistant_model)
raise "pick a supported model" unless provider
# or expose a whitelist endpoint the UI validates against

Type guard

def supported_model?(model_name)
  # mirror of get_model_provider's resolution
  [ Provider::OpenAI, Provider::Anthropic ].any? do |p|
    p.configured? && p.supports_model?(model_name)
  end
end

Try / catch

begin
  Assistant::Builtin.new(chat).respond_to(message)
rescue StandardError => e
  if e.message.start_with?("No LLM provider configured")
    # e.message lists available models: surface as model-picker options
    chat.add_error(e)
  else
    raise
  end
end

Prevention

When it happens

Trigger: Sending an assistant message whose ai_model is a model string no provider advertises: provider settings were changed/removed after older chats picked that model; reopening an old conversation whose stored ai_model was retired/renamed (e.g. gpt-4-turbo-preview deprecated); only one provider configured (OpenAI) while the message requests a claude-* model, or vice versa; a typo'd or user-supplied custom model name that doesn't match the provider's configured list; provider configured but its model list setting doesn't include the custom model name.

Common situations: Self-hosters swapping API keys/providers and forgetting old chats keep their original model; upgrading the app retires a model name upstream providers no longer list; users pasting a model name from the internet; partial configuration — API key present but model allowlist updated.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/b567a3e62cf83c54. Report an issue: GitHub.

Appendix: source

Thrown at app/models/assistant/builtin.rb:25

  class << self
    def for_chat(chat)
      config = config_for(chat)
      new(chat, instructions: config[:instructions], functions: config[:functions])
    end
  end

  def initialize(chat, instructions: nil, functions: [])
    super(chat)
    @instructions = instructions
    @functions = functions
  end

  def respond_to(message, assistant_message: nil)
    assistant_message ||= AssistantMessage.new(chat: chat, content: "", ai_model: message.ai_model)

    llm_provider = get_model_provider(message.ai_model)
    unless llm_provider
      raise StandardError, build_no_provider_error_message(message.ai_model)
    end

    responder = Assistant::Responder.new(
      message: message,
      instructions: instructions,
      function_tool_caller: function_tool_caller,
      llm: llm_provider
    )

    latest_response_id = chat.latest_assistant_response_id

    responder.on(:output_text) do |text|
      if assistant_message.content.blank?
        Chat.transaction do
          assistant_message.append_text!(text)
          chat.update_latest_response!(latest_response_id)
        end
      else

View on GitHub (pinned to e69894adb9)