AWS Lambda costs
How do I stop a runaway AWS Lambda bill?
To stop a runaway Lambda function right now, set its reserved concurrency to 0. That throttles the function instantly, drops incoming executions, and stops any further billing while leaving your code, configuration, and event triggers intact.
Lambda functions rarely run up charges from request volume alone, since requests cost just $0.20 per 1 million in US East (N. Virginia). The real damage happens when high concurrency meets a long execution duration, which burns through GB-seconds at scale or gets stuck in a recursive loop before AWS automatically terminates it at approximately 16 invocations.
The immediate off switch: reserved concurrency 0
If a function is spinning out of control, you don't need to delete it or tear down your infrastructure. Setting reserved concurrency to 0 acts as a hard shutoff valve for that specific function.
AWS provides reserved concurrency at no additional charge. It controls both the floor and the ceiling of your function's capacity, and setting that value to 0 tells Lambda to reject every single invocation attempt. Synchronous callers receive throttling errors, asynchronous events go to retries or dead-letter queues depending on your setup, and your compute billing halts on the spot.
You can set this in the AWS Management Console under the function's Concurrency configuration, or by running this AWS CLI command:
aws lambda put-function-concurrency --function-name your-function-name --reserved-concurrent-executions 0When you figure out the bug and deploy a fix, you can remove the lock by calling aws lambda delete-function-concurrency --function-name your-function-name or by assigning a safe positive number. You can reserve concurrency up to your account's unreserved concurrency limit minus 100, because AWS always reserves 100 concurrency units for functions running without dedicated limits.
If you are dealing with Lambda Web Functions instead of standard Event Functions, AWS gives you a different knob: set the endpoint rate limit (throttleConfig.rateLimit) to 0, which immediately blocks all traffic to that endpoint.
How Lambda billing runs up costs
Lambda Event Functions bill on two core metrics: the number of requests served, and the duration your code runs measured in GB-seconds. The AWS free tier includes 1,000,000 requests and 400,000 GB-seconds every month. Once you clear that margin, the duration charges dominate the invoice.
Duration is calculated from the millisecond your handler starts until it returns or exits, rounded up to the nearest 1 ms. That duration includes initialization code declared outside the handler, your actual handler execution, and the time it takes for any AWS Lambda Extension to finish during shutdown. If you allocated 10,240 MB of memory to a function and it hangs until the maximum 900-second (15-minute) timeout, a single execution consumes 9,000 GB-seconds. Multiply that across dozens of concurrent invocations triggered by an upstream event source, and costs pile up rapidly.
Event payloads matter too. For asynchronous events from services like S3, SNS, EventBridge, Step Functions, and CloudWatch Logs, Lambda bills 1 request for the first 256 KB, and adds another request for every 64 KB chunk beyond that up to 1 MB.
| Component | Setting or limit | US East (N. Virginia) price |
|---|---|---|
| Requests | Per 1,000,000 requests | $0.20 |
| x86 Compute | Per GB-second | $0.0000166667 |
| ARM Compute | Per GB-second | $0.0000133334 |
| Ephemeral Storage | First 512 MB | Included free |
| Extra Storage | 512 MB to 10,240 MB, per GB-second | $0.0000000309 |
| Memory Range | 128 MB to 10,240 MB (1 MB steps) | Changes compute rate |
| Maximum Timeout | Standard Event Function | 900 seconds maximum |
Notice the difference between architectures. Running on ARM processors cuts your compute cost from $0.0000166667 down to $0.0000133334 per GB-second. Memory sizing also adjusts your CPU share: at 1,769 MB, a function gets the equivalent of one full vCPU.
Provisioned Concurrency is another area where bills run away silently. Unlike standard invocations, Provisioned Concurrency bills continuously from the minute you enable it until you turn it off, rounded up to the nearest 5 minutes, and those instances do not qualify for the Lambda free tier.
Recursive loop detection and where it fails
AWS has built-in recursive loop detection for Lambda Event Functions. It is enabled by default across all accounts at no extra charge, and it doesn't need X-Ray active tracing to work.
If Lambda detects that an Event Function has been invoked approximately 16 times in the same chain of requests, it automatically breaks the chain, drops the next invocation, and flags the loop. You can explicitly configure this behavior via the AWS CLI using the put-function-recursion-config command:
aws lambda put-function-recursion-config --function-name your-function-name --recursive-loop TerminateWhile this saves developers from infinite loops in basic setups, you cannot rely on it as a universal safety net. Loop detection only tracks chains between Lambda Event Functions, Amazon SQS, Amazon S3, Amazon SNS, Amazon EventBridge Custom event buses, and direct Lambda-to-Lambda calls.
If another service forms part of the cycle - most commonly Amazon DynamoDB via DynamoDB Streams - Lambda cannot detect or stop the recursion. A function that reads a record, mutates an attribute, and writes it back to DynamoDB will spin forever until someone intervenes.
Loop detection also requires your code to use modern AWS SDKs that forward tracing headers. The minimum required versions include:
- Node.js: 2.1147.0 (v2) or 3.105.0 (v3)
- Python: boto3 1.24.46 / botocore 1.27.46
- Java: 2.17.135 (Java 8/11), 2.20.81 (Java 17), 2.21.24 (Java 21)
- Go: V2 SDK 1.57.0
- .NET: 3.7.293.0
- Ruby: 3.134.0
- PHP: 3.232.0
Even when loop detection fires, SQS queues require extra attention. When Lambda drops an invocation from an SQS loop, it returns a RecursiveInvocationException to the event source mapping. SQS sees this as a failed delivery and keeps retrying the message until your queue's maxReceiveCount is exceeded and routes it to a dead-letter queue. If you didn't configure a dead-letter queue or set maxReceiveCount low, those retries will keep coming.
Notification delays are also substantial. AWS Health Dashboard notices and email alerts for stopped loops can take up to 3.5 hours to arrive, and AWS sends at most one email per function every 24 hours to your primary and alternate operations contacts. By the time you read that email, a bad loop could have run for hours.
Disabling event source mappings
When a queue or stream continuously pushes bad payloads into your function, throttling the function with reserved concurrency 0 protects the compute bill, but you also want to stop the trigger itself.
For event sources like SQS, DynamoDB Streams, or Kinesis, you can disable the event source mapping directly. First, list the mappings to find the identifier:
aws lambda list-event-source-mappings --function-name your-function-nameFind the UUID in the output, then turn off the mapping:
aws lambda update-event-source-mapping --function-name your-function-name --uuid a1b2c3d4-5678-90ab-cdef-EXAMPLE11111 --no-enabledThis pauses event consumption at the source without deleting the stream or your queue items. For Amazon MQ sources, remember that Lambda sets an internal maximum concurrency of 5 for Apache ActiveMQ and 1 for RabbitMQ, and setting reserved or provisioned concurrency on your function does not modify those broker limits.
Defensive limits: timeouts and account quotas
Never leave a Lambda function at the maximum 900-second timeout unless it is running an intentional long-batch workload. If your API endpoint or message processor normally finishes in 800 milliseconds, set your timeout to 5 or 10 seconds. If an external API hangs or a database locks up, the invocation cuts off quickly instead of sitting idle at maximum memory pricing. Standard functions cap at 900 seconds, though asynchronous and event source invocations on AWS Lambda Managed Instances allow up to 5,400 seconds (90 minutes).
Concurrency quotas also protect against unbounded scaling. Every AWS Region starts with a default soft limit of 1,000 concurrent executions across all functions in the account. New accounts often have reduced concurrency and memory quotas that AWS scales up over time based on usage patterns.
For synchronous calls, each execution instance can serve up to 10 requests per second, which means your total synchronous request throughput is capped at 10 times your concurrency limit. Keep an eye on CloudWatch metrics:
ConcurrentExecutions: Tracks the exact number of concurrent instances running per function.InvocationandDuration: Let you calculate estimated concurrency (average requests per second multiplied by average duration in seconds).
Alerts and emergency brakes with Costbrake
Watching CloudWatch graphs manually isn't practical when an issue starts at 2 a.m. Setting up automated alerts helps catch runaways before they eat into your bank account.
Costbrake watches spending across AWS and 22 other cloud, AI, and SaaS providers. For AWS, it reads Cost Explorer along with live CloudWatch estimates for Lambda requests, duration, and other compute resources. With the CloudWatch read permission, Costbrake estimates Lambda requests and duration hourly on the Free plan, every 5 minutes on Pro and Team, and every minute once a spike is detected. A spike alert triggers whenever an hour costs more than 3x the 7-day baseline and at least $5 above normal.
If something breaks, Costbrake has an opt-in, reversible killswitch called brakes on its Pro and Team plans. The Lambda brake sets your function's reserved concurrency to 0 in seconds, stopping all invocations and halting billing without deleting your code or configuration. It only executes when an admin clicks and confirms it.
You can learn more on the Costbrake pricing page or follow the agent setup instructions to connect your account using read-only IAM credentials. For wider architectural patterns on protecting infrastructure, see our guides on what is a cloud killswitch, setting hard limits on AWS, and defending against denial-of-wallet attacks.
Questions and answers
Can a Lambda function run up a massive bill?
Yes. While requests cost only $0.20 per million in US East (N. Virginia), duration costs scale with allocated memory and execution time. If hundreds of concurrent instances hit long timeouts or get trapped in undetected loops, GB-second charges accumulate quickly.
What does setting reserved concurrency to 0 do?
It acts as an immediate off switch by capping the function's maximum and minimum execution capacity to zero. Lambda throttles every incoming request, stopping code execution and halting duration billing while keeping your code, triggers, and configuration unchanged.
Does AWS automatically stop recursive Lambda loops?
AWS stops recursive loops only for supported services like SQS, SNS, S3, EventBridge Custom event buses, and direct Lambda calls once they reach about 16 invocations. If another service like DynamoDB is in the loop, AWS cannot detect it, and the function will continue running.
How long does it take AWS to send a recursive loop alert?
Notifications in the AWS Health Dashboard and emails to account contacts can take up to 3.5 hours to appear after Lambda blocks an invocation. AWS also limits these emails to a maximum of one message per function every 24 hours.
What happens to messages in SQS when a function is throttled?
When Lambda throttles an SQS consumer due to concurrency limits or recursive loop exceptions, the messages remain in the queue and undergo retries. If the failures persist and the message exceeds the queue's maxReceiveCount, SQS moves it to your configured dead-letter queue.
Sources
Updated