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

Your account is not authorized to use the external assistant

Error message

Your account is not authorized to use the external assistant.

What it means

After passing the configured? gate, Assistant::External#respond_to checks self.class.allowed_user?(chat.user) before building the client. When the user isn't on the external assistant's allowlist (the class defines which users may use it — typically admin/restricted-demo policy), it raises Assistant::Error("Your account is not authorized to use the external assistant."). This is an application-level authorization decision, not an HTTP 401 from the remote agent — no network request has been made yet when this raises.

Source

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

        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?
      raise Assistant::Error, "External assistant returned an empty response."
    end

    response_completed = true
    assistant_message.update!(ai_model: model) if model.present?

View on GitHub (pinned to e69894adb9)

Solutions

  1. Confirm with the operator who is allowed: check Assistant::External.allowed_user?(user) in console to see the policy verdict for that exact user
  2. Switch the chat to a permitted assistant/model (the built-in LLM assistant) if your account isn't intended to use the external agent
  3. If you ARE meant to have access, have an admin adjust whatever allowed_user? checks (role/flag) for your account
  4. Close or re-model old chats that still point at 'external-agent' after your role changed — they will keep raising on every send

Example fix

# before
Assistant::External.allowed_user?(chat.user) # => false
chat.messages.create!(content: "hi", ai_model: "external-agent")
# => Assistant::Error: Your account is not authorized to use the external assistant.

# after
if Assistant::External.allowed_user?(chat.user)
  Assistant::External.new(chat).respond_to(message)
else
  message.update!(ai_model: "gpt-4o") # or another permitted model
  Assistant::Builtin.new(chat).respond_to(message)
end
Defensive patterns

Strategy: validation

Validate before calling

# Gate the model choice per user before sending
if message.ai_model == "external-agent" && !Assistant::External.allowed_user?(chat.user)
  # block early with a clear message; offer permitted models instead
  raise Unauthorized, "not allowed for this user"
end

Type guard

def may_use_external_assistant?(user)
  Assistant::External.allowed_user?(user)
end

Try / catch

rescue Assistant::Error => e
  if e.message.include?("not authorized")
    # authorization policy: do not retry; offer model switch
    chat.add_error(e)
    message.update!(ai_model: fallback_model)
  else
    raise
  end
end

Prevention

When it happens

Trigger: A regular (non-permitted) family member selecting the external agent model in the assistant UI; demo deployments where only specific accounts may use the shared agent; a user record that no longer satisfies allowed_user? after a role change (member demoted, admin flag removed) while their existing chat still targets the external model; SSO/user rename that changed whatever identity key allowed_user? matches on.

Common situations: Rolling the external agent out to admins first and members finding the entry point anyway; leftover external-model chats after a user's role changed; multi-family installs with per-user gating; testers using a scratch account that was never allowlisted.

Related errors


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