we-promise/sure · error · StandardError

No LLM provider configured that supports model '#{requested_

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.

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)

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.