TL;DR: Stop hammering the API in a tight loop. Wrap every GetCostAndUsage call in exponential backoff with jitter, follow the pagination marker until it stops coming back, and cut the request volume by caching results and preferring fewer, wider queries. Cost Explorer throttles aggressively, so the client has to be polite or the run dies halfway.

The error that kills the run:

```text
Rate exceeded
```

Returned with an HTTP 400 on GetCostAndUsage, usually five or so requests into a loop with no delay between calls.

1. Add exponential backoff with jitter around the API call so retries spread out instead of retrying in lockstep:
   ```python
   import random, time
   def call_with_backoff(fn, tries=6):
       delay = 1.0
       for attempt in range(tries):
           try:
               return fn()
           except RateExceededError:
               time.sleep(delay + random.uniform(0, delay))
               delay = min(delay * 2, 60.0)
       raise RuntimeError("Cost Explorer kept throttling after retries")
   ```
   Expected: transient throttles clear within a few retries instead of aborting the run.
2. Paginate correctly: keep calling with the returned pagination marker until the response stops including one, and never assume the first page is the whole answer.
   Expected: complete result sets with no silently truncated data.
3. Reduce request volume at the source: request MONTHLY granularity instead of DAILY where the use case allows, widen each time period instead of looping day by day, and cache responses on disk keyed by the request parameters.
   Expected: an order of magnitude fewer API calls for the same report.
4. Serialize the calls: run one Cost Explorer request at a time rather than fanning out threads or parallel workers against the same account.
   Expected: no more self-inflicted throttling from concurrent loops.
5. Re-run the full job and watch for throttle responses in the logs.
   Expected: zero Rate exceeded errors across the whole run, with retries logged but rare.

## Use this when
- GetCostAndUsage returns Rate exceeded partway through a loop
- A rightsizing or reporting job dies after a handful of successful API calls
- The client fires requests with no delay, no retry, and no pagination handling
- Multiple workers query Cost Explorer concurrently against one account

## Not for this skill when
- The error is AccessDeniedException, which is permissions, not throttling
- The call returns successfully but with no data, which is a time-range or availability issue
- You are throttled by the Pricing API or EC2 APIs, which have different limits and patterns

## Variant phrasings
- cost explorer API rate exceeded
- GetCostAndUsage throttling
- cost explorer API limits requests per second
- pagination for GetCostAndUsage

## Why it happens
Cost Explorer is a shared, low-throughput API with strict per-account request limits. A loop that worked fine against EC2's generous limits falls over immediately here because the fifth rapid request trips the throttle. Most client code was written against friendlier APIs and never learned to back off, paginate, or cache, so the first production-scale run is the one that discovers the limit.

## Edge cases
- Backoff without jitter makes parallel workers retry in lockstep and re-throttle as a group; the random spread is load-bearing, not decorative
- Cached data goes stale: billing data lags about a day, so cache keys should include the date and a short TTL, not live forever
- Some SDKs surface throttling as a generic client error rather than a named exception, so match on the Rate exceeded message text too
- Throttling is per account, so two different tools polling the same account share one budget and can throttle each other

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_BzKbMLStAP--GoOJWtsiMQ
