we-promise/sure · warning · Provider::Lunchflow::LunchflowError
rate_limited
rate_limited
Error message
Rate limit exceeded. Please try again later.
What it means
HTTP 429 branch of Provider::Lunchflow#handle_response (app/models/provider/lunchflow.rb:134-135). Thrown as LunchflowError(:rate_limited) with message 'Rate limit exceeded. Please try again later.' when Lunchflow answers 429 — the API key has exceeded its request quota for the current window. The client sets no rate limiter of its own; every public method is one HTTP call, so quota is consumed per call.
Source
Thrown at app/models/provider/lunchflow.rb:135
"Accept" => "application/json"
}
end
def handle_response(response)
case response.code
when 200
JSON.parse(response.body, symbolize_names: true)
when 400
Rails.logger.error "Lunch Flow API: Bad request - #{response.body}"
raise LunchflowError.new("Bad request to Lunch Flow API: #{response.body}", :bad_request)
when 401
raise LunchflowError.new("Invalid API key", :unauthorized)
when 403
raise LunchflowError.new("Access forbidden - check your API key permissions", :access_forbidden)
when 404
raise LunchflowError.new("Resource not found", :not_found)
when 429
raise LunchflowError.new("Rate limit exceeded. Please try again later.", :rate_limited)
else
Rails.logger.error "Lunch Flow API: Unexpected response - Code: #{response.code}, Body: #{response.body}"
raise LunchflowError.new("Failed to fetch data: #{response.code} #{response.message} - #{response.body}", :fetch_failed)
end
end
class LunchflowError < StandardError
attr_reader :error_type
def initialize(message, error_type = :unknown)
super(message)
@error_type = error_type
end
end
end
View on GitHub (pinned to e69894adb9)
Solutions
- Retry with exponential backoff plus jitter, spacing attempts by seconds — the limit window resets on its own.
- Serialize or throttle per-account calls (e.g. a semaphore or a queue with a minimum interval per key).
- Cache responses and widen the sync interval so steady-state request volume stays under quota.
- If sustained volume genuinely exceeds quota, request a higher tier/key limit from Lunchflow or use one key per user connection.
Example fix
// before
accounts.each { |a| client.get_account_balance(a[:id]) }
// after
attempts = 0
begin
attempts += 1
accounts.each { |a| client.get_account_balance(a[:id]) }
rescue Provider::Lunchflow::LunchflowError => e
raise unless e.error_type == :rate_limited && attempts < 5
sleep((2**attempts) + rand(3))
retry
end Defensive patterns
Strategy: retry
Type guard
def rate_limited?(e) e.is_a?(Provider::Lunchflow::LunchflowError) && e.error_type == :rate_limited end
Try / catch
attempts = 0 begin attempts += 1 client.get_account_balance(acct_id) rescue Provider::Lunchflow::LunchflowError => e raise unless e.error_type == :rate_limited && attempts < 5 sleep((2**attempts) + rand(3)) # backoff + jitter retry end
Prevention
- Throttle per-key request rate (token bucket) in the sync job.
- Cache provider responses between sync runs instead of re-fetching.
- Stagger per-account jobs so bursts never overlap.
- Alert on sustained 429s — that is a capacity planning signal.
When it happens
Trigger: Sync loops calling get_account_transactions per account in rapid succession; parallel jobs (Sidekiq threads/processes) sharing one API key; polling get_account_balance at short intervals; backfill scripts iterating wide date ranges account-by-account with no throttling.
Common situations: Growing account counts pushing a nightly sync past the provider quota; multiple environments (staging + production, or several users) sharing one Lunchflow key; retries during an outage amplifying request volume.
Related errors
AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21).
Data as JSON: /api/errors/9f0aeb4c53d1272d.
Report an issue: GitHub.