{"record":{"id":"805236b02f0a9ed8","repo":"we-promise/sure","slug":"fetch-failed-805236","errorCode":"fetch_failed","errorMessage":"Failed to fetch data: #{response.code} #{response.message} - #{response.body}","messagePattern":"Failed to fetch data: #(.+?) #(.+?) - #(.+?)","errorType":"exception","errorClass":"Provider::Mercury::MercuryError","httpStatus":null,"severity":"error","filePath":"app/models/provider/mercury.rb","lineNumber":129,"sourceCode":"      case response.code\n      when 200\n        JSON.parse(response.body, symbolize_names: true)\n      when 400\n        Rails.logger.error \"Mercury API: Bad request - #{response.body}\"\n        raise MercuryError.new(\"Bad request to Mercury API: #{response.body}\", :bad_request)\n      when 401\n        # Parse the error response for more specific messages\n        error_message = parse_error_message(response.body)\n        raise MercuryError.new(error_message, :unauthorized)\n      when 403\n        raise MercuryError.new(\"Access forbidden - check your API token permissions\", :access_forbidden)\n      when 404\n        raise MercuryError.new(\"Resource not found\", :not_found)\n      when 429\n        raise MercuryError.new(\"Rate limit exceeded. Please try again later.\", :rate_limited)\n      else\n        Rails.logger.error \"Mercury API: Unexpected response - Code: #{response.code}, Body: #{response.body}\"\n        raise MercuryError.new(\"Failed to fetch data: #{response.code} #{response.message} - #{response.body}\", :fetch_failed)\n      end\n    end\n\n    def parse_error_message(body)\n      parsed = JSON.parse(body, symbolize_names: true)\n      errors = parsed[:errors] || {}\n\n      case errors[:errorCode]\n      when \"ipNotWhitelisted\"\n        ip = errors[:ip] || \"unknown\"\n        \"IP address not whitelisted (#{ip}). Add your IP to the API token's whitelist in Mercury dashboard.\"\n      when \"noTokenInDBButMaybeMalformed\"\n        \"Invalid token format. Make sure to include the 'secret-token:' prefix.\"\n      else\n        errors[:message] || \"Invalid API token\"\n      end\n    rescue JSON::ParserError\n      \"Invalid API token\"","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/mercury.rb#L111-L147","documentation":"The catch-all branch of Provider::Mercury#handle_response: Mercury returned a status other than 200/400/401/403/404/429 (most commonly 5xx, but also unexpected 3xx or odd 4xx). The message interpolates the raw code, HTTParty message and body, and the code/body are also written to Rails.logger.error before raising, so the log line \"Mercury API: Unexpected response\" is the searchable breadcrumb.","triggerScenarios":"Mercury outage returning 500/502/503; a gateway timeout 504 on a long transactions query with a huge date range; an unexpected 410/422 for a deprecated endpoint; HTTParty returning a non-listed code after following redirects.","commonSituations":"Incidents on api.mercury.com; very wide date ranges in get_account_transactions straining upstream; a new Mercury API version returning 410 Gone on the old path; proxies or corporate gateways injecting 502s.","solutions":["Check the logged body — grep the app log for 'Mercury API: Unexpected response' to get the exact code and upstream message.","Check Mercury status/dashboard for an ongoing incident if the code is 5xx, then retry with backoff after a few minutes.","If 410/405-style codes appear, compare the current Mercury API docs against the path in base_url — the endpoint may have moved.","Narrow the request (smaller date range or pagination) if 504s repeat on heavy queries.","Treat as transient first: this error_type is :fetch_failed, so retry once or twice before surfacing to the user."],"exampleFix":"# before\nresult = provider.get_accounts\n\n# after\nbegin\n  result = provider.get_accounts\nrescue Provider::Mercury::MercuryError => e\n  raise if e.error_type != :fetch_failed || attempt >= 2\n  attempt += 1\n  sleep(30 * attempt)\n  retry\nend","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"begin\n  provider.get_accounts\nrescue Provider::Mercury::MercuryError => e\n  if e.error_type == :fetch_failed && attempts < 2 # often 5xx/transient\n    attempts += 1\n    sleep(60)\n    retry\n  end\n  raise\nend","preventionTips":["Watch the paired 'Mercury API: Unexpected response' log line for the real status before choosing a response.","Keep date windows modest in get_account_transactions to avoid 504-prone heavy queries.","Alert on fetch_failed spikes to catch Mercury incidents early."],"tags":["mercury","http-5xx","unexpected-status","banking-api","transient"],"backgroundTag":"unexpected-http-status","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}