Skip to content

Lambda throttling (Rate exceeded, 429): concurrency limits explained and fixed

Lambda 429 TooManyRequestsException and Rate exceeded errors mean you have hit a concurrency limit. How Lambda concurrency actually works, how to see which limit you hit, and how to fix it.

A Lambda 429 with TooManyRequestsException means invocations are being throttled: the function tried to run more copies simultaneously than a concurrency limit allows. The limit you hit is one of three — the account-wide concurrent execution quota for the region, a reserved concurrency cap on the function itself, or the burst ramp-up rate. Confusingly, Rate exceeded also appears when you hammer Lambda’s management APIs from scripts or Terraform, which is a different problem entirely. Sorting out which one you hit takes about five minutes and determines the fix.

What’s happening

Lambda’s unit of scale is concurrency: the number of invocations executing at the same instant. Three separate limits govern it.

First, the account-level quota: each account gets a pool of concurrent executions per region — the long-standing default is 1,000, but new accounts frequently start much lower until they request an increase. Every function without reserved concurrency draws from this shared pool, and Lambda always keeps a slice of the pool (100) unreserved so functions without reservations cannot be fully starved.

Second, reserved concurrency: a per-function setting that is both a guarantee and a ceiling. Reserve 200 for a function and it can always reach 200 — but it can never exceed 200, and those 200 leave the shared pool.

Third, the burst ramp: even under the account cap, each function can scale up by 1,000 concurrent executions every 10 seconds. A cliff-face spike beyond that rate gets throttled during the ramp even with plenty of quota available.

What a throttle does to your traffic depends on the invocation type. Synchronous callers (API Gateway, ALB, direct invoke) get the 429 back and must retry themselves. Asynchronous invocations are queued by Lambda and retried with backoff for up to six hours before being dropped or dead-lettered. Event source mappings for SQS simply slow their polling — messages wait in the queue, which is usually harmless and exactly what queues are for.

The Rate exceeded message from the AWS CLI or Terraform is usually control-plane API throttling (too many GetFunction or UpdateFunctionConfiguration calls), not invocation throttling. That one is fixed with retries and backoff in the tooling, not with concurrency changes.

What to check first

  • The Throttles metric. Lambda > Functions > (function) > Monitor — if Throttles is zero, your 429 is coming from somewhere else (API Gateway has its own limits).
  • Account-level concurrency in use. One noisy function can eat the whole regional pool and throttle every other function in the account.
  • Reserved concurrency on the affected function. A reservation of 50 set two years ago behaves exactly like this the day traffic grows.
  • Whether someone set reserved concurrency to 0. That is Lambda’s kill switch — it blocks all invocations and every one of them throttles.
  • The traffic shape. A vertical spike (cache stampede, scheduled fan-out, retry storm) can hit the burst ramp even when steady-state concurrency is modest.

How to verify

Check the account pool and the function’s settings:

aws lambda get-account-settings \
  --query 'AccountLimit.ConcurrentExecutions'

aws lambda get-function-concurrency --function-name my-function

Compare usage against the ceiling in CloudWatch — the account-wide ConcurrentExecutions metric in the AWS/Lambda namespace, alongside per-function Throttles:

aws cloudwatch get-metric-statistics \
  --namespace AWS/Lambda --metric-name ConcurrentExecutions \
  --start-time 2026-07-03T00:00:00Z --end-time 2026-07-04T00:00:00Z \
  --period 300 --statistics Maximum

If maximum ConcurrentExecutions kisses the account limit at the same timestamps Throttles spikes, the diagnosis is done. The concurrency model is documented in depth at https://docs.aws.amazon.com/lambda/.

The fix

  1. Raise the account quota if the regional pool is the ceiling. Concurrent executions is an adjustable quota — request the increase through Service Quotas (aws service-quotas request-service-quota-increase --service-code lambda --quota-code L-B99A9384 --desired-value 3000). Modest increases are typically quick; large ones may involve AWS support, and new accounts should do this before launch, not during the incident.
  2. Fix or remove stale reserved concurrency. If the function’s reservation is the cap, raise it deliberately or delete it: aws lambda delete-function-concurrency --function-name my-function. Re-check what else depends on the shared pool before returning the function to it.
  3. Protect critical functions from noisy neighbours. The inverse case: a batch function ate the pool and throttled your payment webhook. Give the critical function reserved concurrency so it always has capacity, and consider capping the batch function too.
  4. Put a queue in front of spiky producers. If bursts outrun the 1,000-per-10-seconds ramp, an SQS queue between producer and function converts the cliff into a slope — the event source mapping drains at whatever concurrency is available.
  5. Tame retry storms. Synchronous callers that retry instantly on 429 make throttling self-sustaining. Enforce exponential backoff with jitter in every client, including your own services.
  6. For CLI/Terraform Rate exceeded, add backoff to the tooling. Configure AWS SDK retry modes (AWS_RETRY_MODE=adaptive, AWS_MAX_ATTEMPTS=10) or serialize the parallelism in CI rather than touching function concurrency at all.

When this is the wrong move

Do not reflexively raise limits when throttling is doing its job. If a misbehaving upstream is fanning out uncontrolled invocations, throttles are the only thing standing between you and a very large bill — setting reserved concurrency to 0 on a runaway function is a legitimate emergency brake. And if an SQS-driven function throttles occasionally while the queue absorbs the wait, that is the system working as designed; only fix it if message age breaches your actual latency requirement.

Common mistakes

  • Requesting a giant quota increase instead of asking why concurrency exploded — the usual answer is a retry loop or a recursive invocation, and more quota just makes the blast radius bigger.
  • Forgetting reserved concurrency subtracts from the shared pool, so “reserving 900 of 1,000 for safety” starves every other function in the region.
  • Treating async throttles as failures — Lambda already queues and retries them; adding client-side retries on top duplicates events.
  • Confusing Lambda throttling with API Gateway throttling. API Gateway account and stage limits produce their own 429s before Lambda is ever invoked.

Prevention

  • Alarm on per-function Throttles greater than zero for critical functions, and on account ConcurrentExecutions above ~80% of the quota — the same alarm philosophy as the rest of the CloudWatch baseline.
  • Review reserved concurrency settings quarterly; they encode last year’s traffic assumptions.
  • Request quota increases as part of launch checklists for new regions and new accounts.
  • Load-test the burst shape, not just the steady state — the ramp limit only shows up under a vertical spike.

Throttling is Lambda telling you precisely which assumption about scale just broke, and the metrics name the assumption if you look. If nobody on your team truly owns the AWS environment end to end, that is the root of most of these problems — Stack Harbor runs AWS accounts daily under AWS Operations, and you can book an AWS review.