we-promise/sure · error · Assistant::Error
External assistant is temporarily unavailable.
Error message
External assistant is temporarily unavailable.
What it means
Raised by Assistant::External::Client#chat when a transient network error occurs BEFORE any content chunk streamed AND the built-in retry budget is exhausted. The client retries transient failures up to MAX_RETRIES = 2 extra attempts with sleep(RETRY_DELAY * retries) backoff (1s then 2s), so this error means 3 total attempts all failed at connect/first-read time.
Source
Thrown at app/models/assistant/external/client.rb:61
model = stream_response(http, request) do |content|
streaming_started = true
block.call(content)
end
model
rescue *TRANSIENT_ERRORS => e
if streaming_started
Rails.logger.warn("[External::Client] Stream interrupted: #{e.class} - #{e.message}")
raise Assistant::Error, "External assistant connection was interrupted."
end
retries += 1
if retries <= MAX_RETRIES
Rails.logger.warn("[External::Client] Transient error (attempt #{retries}/#{MAX_RETRIES}): #{e.class} - #{e.message}")
sleep(RETRY_DELAY * retries)
retry
end
Rails.logger.error("[External::Client] Unreachable after #{MAX_RETRIES + 1} attempts: #{e.class} - #{e.message}")
raise Assistant::Error, "External assistant is temporarily unavailable."
end
end
private
def stream_response(http, request, &block)
model = nil
buffer = +""
done = false
http.request(request) do |response|
unless response.is_a?(Net::HTTPSuccess)
Rails.logger.warn("[External::Client] Upstream HTTP #{response.code}: #{response.body.to_s.truncate(500)}")
raise Assistant::Error, "External assistant returned HTTP #{response.code}."
end
response.read_body do |chunk|
break if doneView on GitHub (pinned to e69894adb9)
Solutions
- Verify the upstream is reachable from the app host: curl -v <same URL> — fix the stopped service or the URL/env configuration.
- Check DNS and egress rules (security groups, firewall) for the app server, and inspect HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars the client honors.
- Retry from the caller with backoff — this failure is safe to retry because nothing was streamed and no side effects occurred.
- If the endpoint is flaky by nature, wrap calls in a circuit breaker so you fail fast instead of burning the full retry ladder on every request.
Example fix
# before
result = client.chat(messages: messages) { |chunk| stream.write(chunk) }
# after — safe outer retry because nothing streamed
attempts = 0
begin
result = client.chat(messages: messages) { |chunk| stream.write(chunk) }
rescue Assistant::Error => e
raise if e.message.exclude?("temporarily unavailable") || (attempts += 1) >= 3
sleep(5 * attempts)
retry
end Defensive patterns
Strategy: retry
Validate before calling
# Cheap reachability check before the call (nothing has streamed, retry is safe) require "socket" require "uri" uri = URI(external_assistant_url) Socket.tcp(uri.host, uri.port, connect_timeout: 3).close
Try / catch
attempts = 0
begin
model = client.chat(messages: messages) { |c| stream.write(c) }
rescue Assistant::Error => e
raise unless e.message.include?("temporarily unavailable") && attempts < 3
attempts += 1
sleep(2**attempts)
retry
end Prevention
- Monitor the external agent's uptime and wire a readiness check so traffic stops before the 3-attempt ladder burns request time.
- Keep HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars correct for the deploy environment — the client honors them when building the connection.
- Use a circuit breaker around chat so sustained outages fail fast instead of retrying on every request.
When it happens
Trigger: client.chat raises Net::OpenTimeout, Errno::ECONNREFUSED, SocketError (bad DNS), EHOSTUNREACH, or ReadTimeout before the first SSE chunk: upstream process down, wrong hostname in @url, port closed, DNS failure, or a proxy in HTTP_PROXY/HTTPS_PROXY refusing the CONNECT. streaming_started stays false through all 3 attempts, falling through to the raise at app/models/assistant/external/client.rb:60-61.
Common situations: External agent service stopped or crashed; wrong EXTERNAL_ASSISTANT URL in env config; DNS not resolving in the deploy environment; a corporate proxy env var pointing at a dead proxy; firewall/security group blocking egress on the target port.
Related errors
- External assistant connection was interrupted.
- External assistant returned HTTP #{response.code}.
- <%= class_name %> API: #{operation_name} failed (attempt #{r
- Lunchflow provider is not configured
- request_failed
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/a772f3faaac65690.
Report an issue: GitHub.