What it means
An AWS account has one pool of concurrent executions per region, and reserved concurrency carves a guaranteed slice out of it for a single function. The slice is guaranteed in both directions: that function can always reach its reservation, and it can never exceed it.
What stops the pool being carved up entirely is a floor. Lambda keeps a minimum amount — conventionally 100 — unreserved, and every function without its own reservation draws from that remainder. If reservations could consume the whole account, one function's configuration change would silently throttle every other function you own, including ones belonging to teams who would have no idea why. The refusal is that protection.
The arithmetic is worth doing explicitly, because reservations are cumulative and nobody sees the total. With a default limit of 1,000 and the 100 floor, there are 900 to distribute. Three functions holding 300 each leave nothing, and the fourth request fails no matter how modest — the error names the floor rather than the functions that consumed the budget, so the cause is somewhere other than where you are looking.
Provisioned concurrency is the part most often missed in that sum. It draws from the same account limit but does not appear in reserved-concurrency figures, so an account can look like it has headroom and not have it.
There is a design point underneath this that is worth taking seriously. Because a reservation is also a cap, an over-generous number is not a free safety margin — it holds capacity away from everything else while providing no benefit to the function itself beyond its actual usage. Sizing from observed concurrent executions rather than from an imagined peak usually resolves this without any quota change at all.
Where you'll see it
Deployment output
Not in CloudWatchThis failure happens before the function runs, so nothing about it reaches CloudWatch Logs — there is no invocation, and no log group entry to find. Once the deployment succeeds and the function starts running, the rest of this index covers what you will see there.
Causes, most likely first
Other functions have already reserved most of the account's concurrency
Add up the reservations across every function in the region and subtract from the account limit. Reservations are cumulative, so the function you are deploying may be modest while the account has very little left to give.
The account's concurrency limit is the default 1,000
Check the account's concurrent-executions quota. A new account starts at 1,000 for the whole region, and a single reservation of a few hundred consumes a large fraction of it before anything else is considered.
Provisioned concurrency is also drawing from the same pool
List provisioned-concurrency configurations as well as reserved ones. Provisioned concurrency counts against the account limit too, so a function with it configured is already holding capacity that does not appear in the reserved figures.
The reservation was sized for peak rather than for need
Compare the requested reservation against the function's actual concurrent executions. A number chosen as a safety margin rather than from measurement is the usual reason a single function asks for most of an account.
Fixes
See what the account has actually committed
Reservations are cumulative and easy to lose track of across a team. This lists every one so the remaining headroom is visible before you ask for more.
bashaws lambda list-functions --query 'Functions[].FunctionName' --output text |
tr '\t' '\n' |
while read -r FN; do
R=$(aws lambda get-function-concurrency --function-name "$FN" \
--query 'ReservedConcurrentExecutions' --output text 2>/dev/null)
[ "$R" != "None" ] && [ -n "$R" ] && printf '%-44s %s\n' "$FN" "$R"
done
aws service-quotas get-service-quota \
--service-code lambda --quota-code L-B99A9384 --query 'Quota.Value'
Reserve from measurement, not from fear
Reserved concurrency is a ceiling as well as a floor — setting it to 500 also caps the function at 500. Size it from observed concurrent executions with headroom, rather than from the largest number that seemed safe.
yamlResources:
IngestFunction:
Type: AWS::Serverless::Function
Properties:
# Observed peak concurrency ~60. This both guarantees and caps.
ReservedConcurrentExecutions: 100
Request a higher account limit when the demand is real
The 1,000 default is adjustable and routinely raised. Where several functions genuinely need large reservations, raising the account limit is the correct answer rather than trimming each one until they fit.
bashaws service-quotas request-service-quota-increase \
--service-code lambda --quota-code L-B99A9384 --desired-value 5000
Release reservations that are no longer needed
A reservation added during an incident and never removed keeps holding capacity indefinitely. Deleting it returns the concurrency to the shared pool immediately.
bashaws lambda delete-function-concurrency --function-name legacy-fn
Also seen as
The same underlying failure, worded differently by a different runtime, SDK version, or logging layer. All of these land here — there is no separate page for each phrasing.
Related errors
Errors that show up alongside this one, or that people mistake for it.
References
- AWS Lambda Developer Guide — Configuring reserved concurrency
- AWS Lambda Developer Guide — Lambda quotas
This one happens before there are any logs.
LogStitch reads CloudWatch, and a deployment that fails never writes to it — so this is not an error it can find for you. Once the function deploys and starts running, the free web stitcher groups its invocations in your browser, and the Mac app does the same across every function in your account.