{"record":{"id":"ac6cd82b1495883b","repo":"we-promise/sure","slug":"bad-request-ac6cd8","errorCode":"bad_request","errorMessage":"Bad request to Lunch Flow API: #{response.body}","messagePattern":"Bad request to Lunch Flow API: #(.+?)","errorType":"exception","errorClass":"LunchflowError","httpStatus":400,"severity":"error","filePath":"app/models/provider/lunchflow.rb","lineNumber":127,"sourceCode":"  end\n\n  private\n\n    def auth_headers\n      {\n        \"x-api-key\" => api_key,\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 \"Lunch Flow API: Bad request - #{response.body}\"\n        raise LunchflowError.new(\"Bad request to Lunch Flow API: #{response.body}\", :bad_request)\n      when 401\n        raise LunchflowError.new(\"Invalid API key\", :unauthorized)\n      when 403\n        raise LunchflowError.new(\"Access forbidden - check your API key permissions\", :access_forbidden)\n      when 404\n        raise LunchflowError.new(\"Resource not found\", :not_found)\n      when 429\n        raise LunchflowError.new(\"Rate limit exceeded. Please try again later.\", :rate_limited)\n      else\n        Rails.logger.error \"Lunch Flow API: Unexpected response - Code: #{response.code}, Body: #{response.body}\"\n        raise LunchflowError.new(\"Failed to fetch data: #{response.code} #{response.message} - #{response.body}\", :fetch_failed)\n      end\n    end\n\n    class LunchflowError < StandardError\n      attr_reader :error_type\n\n      def initialize(message, error_type = :unknown)","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/lunchflow.rb#L109-L145","documentation":"HTTP 400 branch of Provider::Lunchflow#handle_response (app/models/provider/lunchflow.rb:125-127). Thrown as LunchflowError(:bad_request) whenever the Lunchflow API answers GET endpoints with status 400; the raw response body is embedded in both the Rails log ('Lunch Flow API: Bad request - ...') and the error message, so the server-side validation message is visible.","triggerScenarios":"GET /accounts/:id/transactions or /holdings with query parameters the server rejects: unsupported parameter combinations (e.g. include_pending=true on an endpoint that ignores/rejects it), a date range the server deems too wide, or an account id segment that fails server-side validation even after ERB::Util.url_encode. Since the client coerces dates with #to_date, malformed dates usually fail client-side first (surfacing as :request_failed instead), so a 400 here is genuine server-side validation.","commonSituations":"Provider API version change tightening parameter validation (base_url pinned to an old /api/v1 path); syncing with parameter combos that worked in sandbox but not production; account ids copied from another provider or environment.","solutions":["Read the embedded response body in the error message and the 'Lunch Flow API: Bad request' log line — Lunchflow states exactly which parameter failed.","Echo the exact request (path + query string from logs) with curl and adjust the parameters until the server accepts them.","Normalize inputs before calling: Date objects for start/end, trimmed account_id strings, and omit params you do not need.","If the body mentions an unknown parameter, check whether a base_url override points to an outdated API version."],"exampleFix":"// before\nclient.get_account_transactions(acct_id, start_date: from, end_date: to, include_pending: true)\n\n// after (send only supported, validated params)\nparams = { start_date: from.to_date.to_s, end_date: to.to_date.to_s }\nclient.get_account_transactions(acct_id.to_s.strip, **params.reject { |_, v| v.blank? })","handlingStrategy":"validation","validationCode":"raise ArgumentError, 'account_id required' if acct_id.blank?\nraise ArgumentError, 'start after end' if from && to && from > to\nparams = { start_date: from&.to_date, end_date: to&.to_date }.compact","typeGuard":"def bad_request?(e)\n  e.is_a?(Provider::Lunchflow::LunchflowError) && e.error_type == :bad_request\nend","tryCatchPattern":"begin\n  client.get_account_transactions(acct_id, **params)\nrescue Provider::Lunchflow::LunchflowError => e\n  raise unless e.error_type == :bad_request\n  log_to_debug_entries(e.message) # body contains the server's reason\n  skip_account(acct_id)\nend","preventionTips":["Send only parameters the endpoint documents; omit nils.","Always pass Date objects and let the client serialize.","Never retry a 400 — fix the request shape instead."],"tags":["lunchflow","http-400","validation","api","ruby"],"backgroundTag":"http-400-bad-request","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}