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
    raise

View on GitHub (pinned to e69894adb9)

Solutions

  1. Read the log line 'Mercury API: GET /accounts failed: <Class>: <message>' to classify DNS vs timeout.
  2. From the app host run: curl -v https://api.mercury.com/api/v1/accounts (expect 401, which still proves connectivity).
  3. Fix resolver/egress (proxy env vars HTTP(S)_PROXY, firewall rules) as indicated.
  4. 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

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.