{"record":{"id":"db62f783f434971f","repo":"we-promise/sure","slug":"external-assistant-is-not-configured-set-the-url","errorCode":null,"errorMessage":"External assistant is not configured. Set the URL and token in Settings > Self-Hosting or via environment variables.","messagePattern":"External assistant is not configured\\. Set the URL and token in Settings > Self-Hosting or via environment variables\\.","errorType":"exception","errorClass":"Assistant::Error","httpStatus":null,"severity":"error","filePath":"app/models/assistant/external.rb","lineNumber":41,"sourceCode":"      allowed.split(\",\").map { |e| e.strip.downcase }.include?(user.email.downcase)\n    end\n\n    def config\n      Config.new(\n        url: ENV[\"EXTERNAL_ASSISTANT_URL\"].presence || Setting.external_assistant_url.presence,\n        token: ENV[\"EXTERNAL_ASSISTANT_TOKEN\"].presence || Setting.external_assistant_token.presence,\n        agent_id: ENV[\"EXTERNAL_ASSISTANT_AGENT_ID\"].presence || Setting.external_assistant_agent_id.presence || \"main\",\n        session_key: ENV.fetch(\"EXTERNAL_ASSISTANT_SESSION_KEY\", \"agent:main:main\")\n      )\n    end\n  end\n\n  def respond_to(message, assistant_message: nil)\n    response_completed = false\n    assistant_message ||= AssistantMessage.new(chat: chat, content: \"\", ai_model: \"external-agent\")\n\n    unless self.class.configured?\n      raise Assistant::Error,\n        \"External assistant is not configured. Set the URL and token in Settings > Self-Hosting or via environment variables.\"\n    end\n\n    unless self.class.allowed_user?(chat.user)\n      raise Assistant::Error, \"Your account is not authorized to use the external assistant.\"\n    end\n\n    client = build_client\n    messages = build_conversation_messages\n\n    model = client.chat(\n      messages: messages,\n      user: \"sure-family-#{chat.user.family_id}\"\n    ) do |text|\n      assistant_message.append_text!(text)\n    end\n\n    if assistant_message.content.blank?","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/assistant/external.rb#L23-L59","documentation":"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).","triggerScenarios":"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).","commonSituations":"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.","solutions":["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)","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","If using the UI, re-open Settings > Self-Hosting and verify the token field actually saved (it's encrypted/blanked on re-render)","Verify in console: Assistant::External.configured? must return true before chatting (it checks exactly what respond_to checks)"],"exampleFix":"# before\n# .env.local has nothing; Settings UI never opened\nAssistant::External.new(chat).respond_to(message)\n# => Assistant::Error: External assistant is not configured. Set the URL and token in ...\n\n# after (either)\n# 1) ENV: EXTERNAL_ASSISTANT_URL=https://agents.internal EXTERNAL_ASSISTANT_TOKEN=secret\n# 2) UI:   Settings > Self-Hosting > External assistant URL + token saved\nAssistant::External.configured? # => true\nAssistant::External.new(chat).respond_to(message)","handlingStrategy":"validation","validationCode":"# Gate the UI/entry point on the same check respond_to uses\nunless Assistant::External.configured?\n  # hide/disable the external agent option, or link to Settings > Self-Hosting\n  render json: { error: \"external assistant not configured\" }, status: :service_unavailable\nend","typeGuard":"def external_assistant_ready?\n  Assistant::External.configured?\nend","tryCatchPattern":"rescue Assistant::Error => e\n  if e.message.include?(\"not configured\")\n    # config problem, not a chat problem: link the user to Settings > Self-Hosting\n    chat.add_error(e)\n  else\n    raise\n  end\nend","preventionTips":["Set URL and token together, in one source (ENV xor Settings UI)","Verify ENV vars are present in web AND background processes after deploys","Add a boot health check: fail fast at startup if the external agent is selected but unconfigured","Smoke-test Assistant::External.configured? in your environment checklist"],"tags":["rails","assistant","configuration","env-vars","self-hosting"],"backgroundTag":"external-service-not-configured","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}