we-promise/sure · error · Assistant::Error

External assistant is not configured. Set the URL and token

Error message

External assistant is not configured. Set the URL and token in Settings > Self-Hosting or via environment variables.

What it means

Assistant::External is the bridge to a self-hosted external agent: it reads EXTERNAL_ASSISTANT_URL/TOKEN/AGENT_ID from ENV first, falling back to Setting values (session key EXTERNAL_ASSISTANT_SESSION_KEY, default agent 'main'). respond_to first checks self.class.configured?; if no URL or no token resolves from either source, it raises Assistant::Error with this guidance message pointing at Settings > Self-Hosting or environment variables. This fires before any network call — it is purely a configuration gate (URL and token are both required; agent_id defaults, session key defaults).

Source

Thrown at app/models/assistant/external.rb:41

      allowed.split(",").map { |e| e.strip.downcase }.include?(user.email.downcase)
    end

    def config
      Config.new(
        url: ENV["EXTERNAL_ASSISTANT_URL"].presence || Setting.external_assistant_url.presence,
        token: ENV["EXTERNAL_ASSISTANT_TOKEN"].presence || Setting.external_assistant_token.presence,
        agent_id: ENV["EXTERNAL_ASSISTANT_AGENT_ID"].presence || Setting.external_assistant_agent_id.presence || "main",
        session_key: ENV.fetch("EXTERNAL_ASSISTANT_SESSION_KEY", "agent:main:main")
      )
    end
  end

  def respond_to(message, assistant_message: nil)
    response_completed = false
    assistant_message ||= AssistantMessage.new(chat: chat, content: "", ai_model: "external-agent")

    unless self.class.configured?
      raise Assistant::Error,
        "External assistant is not configured. Set the URL and token in Settings > Self-Hosting or via environment variables."
    end

    unless self.class.allowed_user?(chat.user)
      raise Assistant::Error, "Your account is not authorized to use the external assistant."
    end

    client = build_client
    messages = build_conversation_messages

    model = client.chat(
      messages: messages,
      user: "sure-family-#{chat.user.family_id}"
    ) do |text|
      assistant_message.append_text!(text)
    end

    if assistant_message.content.blank?

View on GitHub (pinned to e69894adb9)

Solutions

  1. Set both values in ONE place consistently: either ENV (EXTERNAL_ASSISTANT_URL and EXTERNAL_ASSISTANT_TOKEN — plus optional EXTERNAL_ASSISTANT_AGENT_ID / EXTERNAL_ASSISTANT_SESSION_KEY) or Settings > Self-Hosting (External assistant URL + token)
  2. If using ENV, confirm the vars are visible to every process that runs chats (web and Sidekiq): ENV['EXTERNAL_ASSISTANT_URL'].present? in each context
  3. If using the UI, re-open Settings > Self-Hosting and verify the token field actually saved (it's encrypted/blanked on re-render)
  4. Verify in console: Assistant::External.configured? must return true before chatting (it checks exactly what respond_to checks)

Example fix

# before
# .env.local has nothing; Settings UI never opened
Assistant::External.new(chat).respond_to(message)
# => Assistant::Error: External assistant is not configured. Set the URL and token in ...

# after (either)
# 1) ENV: EXTERNAL_ASSISTANT_URL=https://agents.internal EXTERNAL_ASSISTANT_TOKEN=secret
# 2) UI:   Settings > Self-Hosting > External assistant URL + token saved
Assistant::External.configured? # => true
Assistant::External.new(chat).respond_to(message)
Defensive patterns

Strategy: validation

Validate before calling

# Gate the UI/entry point on the same check respond_to uses
unless Assistant::External.configured?
  # hide/disable the external agent option, or link to Settings > Self-Hosting
  render json: { error: "external assistant not configured" }, status: :service_unavailable
end

Type guard

def external_assistant_ready?
  Assistant::External.configured?
end

Try / catch

rescue Assistant::Error => e
  if e.message.include?("not configured")
    # config problem, not a chat problem: link the user to Settings > Self-Hosting
    chat.add_error(e)
  else
    raise
  end
end

Prevention

When it happens

Trigger: Selecting the external agent in the assistant UI on a fresh install (neither ENV nor Setting has URL/token); setting EXTERNAL_ASSISTANT_URL in ENV but forgetting EXTERNAL_ASSISTANT_TOKEN (presence check fails on token); configuring via Settings UI but the encrypted token Setting saved blank; deploying with dotenv in web but not in the Sidekiq/background process, so chats created from a job see a different (empty) environment; values present but whitespace-only (presence fails).

Common situations: Split ENV propagation between Rails server and background workers; the encrypted-attributes setting not persisted because the form key was omitted; migrating from ENV to UI settings (or back) and leaving both sides blank after a cleanup; staging configured, production not, and traffic hitting production.

Related errors


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