we-promise/sure · warning · Provider::Coinbase::RateLimitError

Rate limit exceeded

Error message

Rate limit exceeded

What it means

Raised by Provider::Coinbase#handle_response when Coinbase returns HTTP 429. Coinbase rate-limits per API key and per endpoint family (private endpoints have point/second budgets). The client raises Provider::Coinbase::RateLimitError with the fixed message "Rate limit exceeded"; no Retry-After details are propagated.

Source

Thrown at app/models/provider/coinbase.rb:203

    def auth_headers(method, path)
      {
        "Authorization" => "Bearer #{generate_jwt(method, path)}",
        "Content-Type" => "application/json"
      }
    end

    def handle_response(response)
      parsed = response.parsed_response

      case response.code
      when 200..299
        parsed.is_a?(Hash) ? parsed : { "data" => parsed }
      when 401
        error_msg = extract_error_message(parsed) || "Unauthorized - check your API key and secret"
        raise AuthenticationError, error_msg
      when 429
        raise RateLimitError, "Rate limit exceeded"
      else
        error_msg = extract_error_message(parsed) || "API error: #{response.code}"
        raise ApiError, error_msg
      end
    end

    def extract_error_message(parsed)
      return parsed if parsed.is_a?(String)
      return nil unless parsed.is_a?(Hash)

      parsed.dig("errors", 0, "message") || parsed["error"] || parsed["message"]
    end
end

View on GitHub (pinned to e69894adb9)

Solutions

  1. Retry with exponential backoff (start ~1-2s) and jitter; treat 429 as transient, never fail the job on first hit.
  2. Space out polling/pagination with a minimum interval between Coinbase calls.
  3. Reduce concurrency: serialize Coinbase requests per API key (single worker or mutex).
  4. Cache responses where possible (balances/price snapshots) to lower call volume.
  5. If limits are chronically hit, request a rate-limit increase for the CDP key.

Example fix

# before
accounts = provider.get_accounts

# after
attempts = 0
begin
  attempts += 1
  accounts = provider.get_accounts
rescue Provider::Coinbase::RateLimitError
  raise if attempts >= 5
  sleep((2**attempts) + rand)
  retry
end
Defensive patterns

Strategy: retry

Type guard

def coinbase_rate_limited?(err)
  err.is_a?(Provider::Coinbase::RateLimitError)
end

Try / catch

attempts = 0
begin
  attempts += 1
  accounts = provider.get_accounts
rescue Provider::Coinbase::RateLimitError
  raise if attempts >= 5
  sleep((2**attempts) + rand)
  retry
end

Prevention

When it happens

Trigger: Polling account balances or prices in a tight loop; paginating many accounts/transactions without a delay; multiple jobs or app instances sharing the same API key; bursts after a deploy restarts several sync workers at once.

Common situations: Sync schedulers that fan out per-account Coinbase calls concurrently; retry storms where a timed-out call is immediately retried and compounds the limit; shared keys between production and side projects; upgrading plans/limits without adjusting poll frequency.

Related errors


AI-assisted analysis of we-promise/sure@e69894adb9 (2026-08-21). Data as JSON: /api/errors/065a9a5dd2541bb7. Report an issue: GitHub.