{"record":{"id":"3531e61604cf2bf2","repo":"we-promise/sure","slug":"bad-request-3531e6","errorCode":"bad_request","errorMessage":"Bad request to Mercury API: #{response.body}","messagePattern":"Bad request to Mercury API: #(.+?)","errorType":"exception","errorClass":"Provider::Mercury::MercuryError","httpStatus":400,"severity":"error","filePath":"app/models/provider/mercury.rb","lineNumber":116,"sourceCode":"  end\n\n  private\n\n    def auth_headers\n      {\n        \"Authorization\" => \"Bearer #{token}\",\n        \"Content-Type\" => \"application/json\",\n        \"Accept\" => \"application/json\"\n      }\n    end\n\n    def handle_response(response)\n      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)","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/mercury.rb#L98-L134","documentation":"HTTP 400 branch of Provider::Mercury#handle_response (app/models/provider/mercury.rb:114-116). Thrown as MercuryError(:bad_request) whenever Mercury answers with 400; the raw response body is embedded in the error message and logged ('Mercury API: Bad request - ...'). For Mercury this typically means the query string built at lines 63-82 violates API constraints: invalid parameter values or types.","triggerScenarios":"get_account_transactions with limit exceeding Mercury's maximum page size (500), limit/offset zero or negative, dates that survive #to_date but are rejected server-side, or a malformed account UUID in the path; any GET /accounts or /account/{id} call when Mercury changes request validation rules.","commonSituations":"Hard-coded limit above the API maximum after a provider policy change; offset math bugs producing negatives during pagination; account ids imported from another provider or truncated; date boundaries like start > end.","solutions":["Read the embedded body in the error message — Mercury states the exact offending parameter.","Clamp pagination params: limit between 1 and 500, offset >= 0, before calling.","Validate the account_id format (Mercury account UUIDs) and refresh via get_accounts if suspect.","Ensure start_date <= end_date and both are real dates."],"exampleFix":"// before\nclient.get_account_transactions(acct_id, offset: params[:offset], limit: params[:limit])\n\n// after\nlimit  = [[params[:limit].to_i, 1].max, 500].min\noffset = [params[:offset].to_i, 0].max\nclient.get_account_transactions(acct_id.to_s, offset: offset, limit: limit)","handlingStrategy":"validation","validationCode":"limit  = [[limit.to_i, 1].max, 500].min   # Mercury max page size\noffset = [offset.to_i, 0].max\nraise ArgumentError, 'start after end' if from && to && from > to","typeGuard":"def bad_request?(e)\n  e.is_a?(Provider::Mercury::MercuryError) && e.error_type == :bad_request\nend","tryCatchPattern":"begin\n  client.get_account_transactions(acct_id, offset: offset, limit: limit)\nrescue Provider::Mercury::MercuryError => e\n  raise unless e.error_type == :bad_request\n  DebugLogEntry.capture(category: 'mercury', level: 'error',\n                        message: e.message, provider_key: 'mercury')\n  skip_account(acct_id)\nend","preventionTips":["Clamp limit to 1..500 and offset to >= 0 in one shared helper used by every caller.","Validate account ids against get_accounts output before detail calls.","Never retry 400s — log the embedded body and fix the parameter."],"tags":["mercury","http-400","pagination","validation","api"],"backgroundTag":"http-400-bad-request","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}