we-promise/sure · error · Provider::Mercury::MercuryError
request_failed
request_failed
Error message
Exception during GET request: #{e.message} What it means
Transport-failure rescue in Provider::Mercury#get_accounts (app/models/provider/mercury.rb:27-29). Raised as MercuryError(:request_failed) when the HTTParty GET to https://api.mercury.com/api/v1/accounts fails with SocketError (DNS), Net::OpenTimeout (connect), or Net::ReadTimeout (idle beyond the 120-second class timeout at line 6). Note MercuryError itself is re-raised untouched at lines 25-26, so this line is reached only for genuine transport faults, never masked status errors.
Source
Thrown at app/models/provider/mercury.rb:29
@token = token
@base_url = base_url
end
# Get all accounts
# Returns: { accounts: [...] }
# Account structure: { id, name, currentBalance, availableBalance, status, type, kind, legalBusinessName, nickname }
def get_accounts
response = self.class.get(
"#{@base_url}/accounts",
headers: auth_headers
)
handle_response(response)
rescue MercuryError
raise
rescue SocketError, Net::OpenTimeout, Net::ReadTimeout => e
Rails.logger.error "Mercury API: GET /accounts failed: #{e.class}: #{e.message}"
raise MercuryError.new("Exception during GET request: #{e.message}", :request_failed)
rescue => e
Rails.logger.error "Mercury API: Unexpected error during GET /accounts: #{e.class}: #{e.message}"
raise MercuryError.new("Exception during GET request: #{e.message}", :request_failed)
end
# Get a single account by ID
# Returns: { id, name, currentBalance, availableBalance, status, type, kind, ... }
def get_account(account_id)
path = "/account/#{ERB::Util.url_encode(account_id.to_s)}"
response = self.class.get(
"#{@base_url}#{path}",
headers: auth_headers
)
handle_response(response)
rescue MercuryError
raiseView on GitHub (pinned to e69894adb9)
Solutions
- Read the log line 'Mercury API: GET /accounts failed: <Class>: <message>' to classify DNS vs timeout.
- From the app host run: curl -v https://api.mercury.com/api/v1/accounts (expect 401, which still proves connectivity).
- Fix resolver/egress (proxy env vars HTTP(S)_PROXY, firewall rules) as indicated.
- Retry with backoff — transport faults to a healthy API are usually transient.
Example fix
// before client.get_accounts // after attempts = 0 begin attempts += 1 client.get_accounts rescue Provider::Mercury::MercuryError => e raise unless e.error_type == :request_failed && attempts < 3 sleep(2**attempts) retry end
Defensive patterns
Strategy: retry
Validate before calling
require 'socket'
TCPSocket.new('api.mercury.com', 443).close # quick egress check before a sync run Type guard
def request_failed?(e) e.is_a?(Provider::Mercury::MercuryError) && e.error_type == :request_failed end
Try / catch
attempts = 0 begin attempts += 1 client.get_accounts rescue Provider::Mercury::MercuryError => e raise unless e.error_type == :request_failed && attempts < 3 sleep(2**attempts + rand(2)) retry end
Prevention
- Whitelist the app's egress IP and open api.mercury.com:443 in firewalls.
- Run one connectivity canary before fan-out syncs.
- In Mercury's dashboard, whitelist the server IPs for the API token (Mercury enforces IP allowlists).
When it happens
Trigger: client.get_accounts when DNS cannot resolve api.mercury.com; egress to api.mercury.com:443 blocked by firewall/proxy; Mercury outage; response stalling past 120s. The Bearer token (Authorization header) plays no role here — the request never completed.
Common situations: Corporate proxy intercepting traffic; container/VM DNS misconfiguration; Mercury API maintenance; on-prem hosts with IPv6-first resolution that fails; local development with no internet.
Related errors
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/57434b51935fd29a.
Report an issue: GitHub.