{"record":{"id":"57434b51935fd29a","repo":"we-promise/sure","slug":"request-failed-57434b","errorCode":"request_failed","errorMessage":"Exception during GET request: #{e.message}","messagePattern":"Exception during GET request: #(.+?)","errorType":"exception","errorClass":"Provider::Mercury::MercuryError","httpStatus":null,"severity":"error","filePath":"app/models/provider/mercury.rb","lineNumber":29,"sourceCode":"    @token = token\n    @base_url = base_url\n  end\n\n  # Get all accounts\n  # Returns: { accounts: [...] }\n  # Account structure: { id, name, currentBalance, availableBalance, status, type, kind, legalBusinessName, nickname }\n  def get_accounts\n    response = self.class.get(\n      \"#{@base_url}/accounts\",\n      headers: auth_headers\n    )\n\n    handle_response(response)\n  rescue MercuryError\n    raise\n  rescue SocketError, Net::OpenTimeout, Net::ReadTimeout => e\n    Rails.logger.error \"Mercury API: GET /accounts failed: #{e.class}: #{e.message}\"\n    raise MercuryError.new(\"Exception during GET request: #{e.message}\", :request_failed)\n  rescue => e\n    Rails.logger.error \"Mercury API: Unexpected error during GET /accounts: #{e.class}: #{e.message}\"\n    raise MercuryError.new(\"Exception during GET request: #{e.message}\", :request_failed)\n  end\n\n  # Get a single account by ID\n  # Returns: { id, name, currentBalance, availableBalance, status, type, kind, ... }\n  def get_account(account_id)\n    path = \"/account/#{ERB::Util.url_encode(account_id.to_s)}\"\n\n    response = self.class.get(\n      \"#{@base_url}#{path}\",\n      headers: auth_headers\n    )\n\n    handle_response(response)\n  rescue MercuryError\n    raise","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/mercury.rb#L11-L47","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nclient.get_accounts\n\n// after\nattempts = 0\nbegin\n  attempts += 1\n  client.get_accounts\nrescue Provider::Mercury::MercuryError => e\n  raise unless e.error_type == :request_failed && attempts < 3\n  sleep(2**attempts)\n  retry\nend","handlingStrategy":"retry","validationCode":"require 'socket'\nTCPSocket.new('api.mercury.com', 443).close # quick egress check before a sync run","typeGuard":"def request_failed?(e)\n  e.is_a?(Provider::Mercury::MercuryError) && e.error_type == :request_failed\nend","tryCatchPattern":"attempts = 0\nbegin\n  attempts += 1\n  client.get_accounts\nrescue Provider::Mercury::MercuryError => e\n  raise unless e.error_type == :request_failed && attempts < 3\n  sleep(2**attempts + rand(2))\n  retry\nend","preventionTips":["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)."],"tags":["mercury","httparty","timeout","dns","network","ruby"],"backgroundTag":"connection-timeout","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}