skip to content

Invocation Models and Retries

Lambda behaves very differently depending on how it is invoked, and the retry story follows from that. I learn synchronous RequestResponse versus asynchronous Event invokes, who retries what, and where a failed event finally lands.

part ofAWSoverview, primer and where to startread it →
on this pageshow

questions

6

In AWS Lambda, what is the difference between invoking a function with InvocationType RequestResponse and InvocationType Event, and who is responsible for retrying a failure in each case?

level: juniorimportance: must knowfreq 82%

answer

  1. the caller's wait changes everything
  2. one hands back a payload, one a receipt
  3. InvocationType RequestResponse versus Event
  4. 202 Accepted means queued, not done
  5. whoever holds the error does the retrying

basics

~20 s

RequestResponse is synchronous: the caller waits, receives the function's result or error, and must retry itself. Event is asynchronous: Lambda returns 202 immediately, queues the event internally, and retries a failed invocation on your behalf.

solid answer

~50 s

The `InvocationType` parameter on the Lambda `Invoke` API decides the whole shape of the interaction. With `RequestResponse` — the default — the caller's connection stays open for the duration of the execution, and the function's return value or error payload comes back in the response. Nothing in AWS retries an application error here; the caller owns that decision, and callers like API Gateway simply surface the failure. With `Event`, Lambda writes the event into an internal, AWS-managed queue and returns HTTP 202 with an empty body before the function has run. The caller never sees the result, success or failure. Lambda then invokes the function from that queue and, if the handler errors, retries it a couple of times before giving up. So the practical question is not "is it faster?" but "who is holding the error when it happens" — the caller, or AWS.

code

bash · 4 lines
bash
aws lambda invoke --function-name my-function \
  --invocation-type Event \
  --payload '{"orderId":"123"}' \
  --cli-binary-format raw-in-base64-out /dev/null

go deeper

for a junior

Know the two InvocationType values by name and say plainly what comes back from each: a payload from RequestResponse, an empty 202 from Event. Add that Lambda retries only the asynchronous path.

for a middle

Be ready to explain the mechanics behind the split — the AWS-managed queue behind Event, the FunctionError field on a 200 response, and why a synchronous caller sees latency the asynchronous one never does.

for a senior

Show the operational consequence: with Event you have no response channel, so failure visibility has to be engineered with destinations and metrics. Say how you would detect a function silently failing on the asynchronous path.

for a principal

Own the choice as an architectural one. Argue when a user-facing request should degrade into queued work, what that does to the consistency the client can rely on, and how the invocation model shapes the blast radius of a downstream outage.

## One parameter, two completely different contracts Every direct call into Lambda goes through the `Invoke` API action, and that action takes an `InvocationType` parameter with three legal values: `RequestResponse` (the default), `Event`, and `DryRun`. Everything else in this area — timeouts, error handling, retries, where a failed payload ends up — follows from which of those you chose. ## RequestResponse: the caller waits and owns the error With `RequestResponse`, the API call blocks while the function runs. When the handler returns, its serialized return value comes back as the response payload. The caller sees the latency of a cold start, of the handler body, and of every downstream call the handler makes. The trap here is that a *function* error is not a *request* error. If the handler throws, the `Invoke` call still returns HTTP 200. What tells you something went wrong is the `FunctionError` field in the response (set to `Handled` or `Unhandled`) and the `X-Amz-Function-Error` header; the payload then contains the serialized error rather than your result. Code that checks only the HTTP status will treat every crash as a success. ```bash aws lambda invoke --function-name my-function \ --invocation-type RequestResponse \ --payload '{"orderId":"123"}' \ --cli-binary-format raw-in-base64-out out.json ``` Nothing on the AWS side retries an application error on this path. AWS SDKs do retry — but only for the errors their retry policy covers, such as throttling and service-side 5xx responses, not for your handler blowing up. Services that invoke synchronously (API Gateway, an Application Load Balancer target, a function URL) pass the failure straight back to whoever called them. ## Event: Lambda takes custody of the event With `Event`, Lambda validates the request, writes the payload into an internal queue that AWS manages for you, and returns HTTP 202 Accepted with an empty body — typically in a few milliseconds, long before the function has started. There is no channel back to the caller: the return value is discarded, and so is the error. In exchange, Lambda owns delivery. It pulls from that queue, invokes the function, and if the invocation fails it retries. It also keeps retrying when the invocation is *throttled* rather than broken, which is what makes asynchronous invocation a natural shock absorber for bursty producers. Because the result is invisible to the caller, an asynchronously invoked function that matters must have somewhere for failures to land — a destination or dead-letter target — or the event simply disappears. ```bash aws lambda invoke --function-name my-function \ --invocation-type Event \ --payload '{"orderId":"123"}' \ --cli-binary-format raw-in-base64-out /dev/null ``` ## DryRun: the third value people forget `DryRun` validates the request — parameters and the caller's permission to invoke — without running the function, and returns HTTP 204 No Content. It is a permissions smoke test, not a way to "test" your handler. ## Which callers use which You rarely choose the invocation type by hand for event-driven functions; the calling service chose it for you. Front-door, request-shaped integrations invoke synchronously because someone is waiting for a response: API Gateway, an ALB, a function URL. Fire-and-forget event producers such as SNS and EventBridge invoke asynchronously. Poller-based sources are a third mechanism entirely, with their own batching and failure semantics. When *you* are writing the caller, pick on the question of who should be holding the error. If the client needs the answer to proceed, invoke synchronously and design the caller's retry and timeout behaviour deliberately. If the client only needs the work to eventually happen, invoke asynchronously so a brief downstream outage becomes a retry rather than a user-visible 500 — and accept that you must observe failures through metrics and a failure destination instead of a response body. ## Consequences people miss Asynchronous invocation is not faster; it just moves the wait. It is *at least once*, so handlers must tolerate seeing the same event twice. And a synchronous caller that retries on timeout may be retrying work that actually succeeded, because a timed-out response says nothing about whether the function finished.

  • What does InvocationType DryRun actually do?
    It validates the request without executing the function: Lambda checks the parameters and whether the caller is permitted to invoke, then returns HTTP 204 No Content. It is a way to verify permissions and wiring in a deployment check, not a way to test handler logic — the handler never runs and no execution is billed.
  • A synchronous Invoke returns HTTP 200. What must the caller still check before treating it as success?
    The `FunctionError` field on the response, or the `X-Amz-Function-Error` header. Lambda returns 200 as long as it managed to run the function at all; a handler that threw produces a 200 whose payload is the serialized error, with `FunctionError` set to `Handled` or `Unhandled`. Status-code-only error handling silently swallows every crash.
  • Does asynchronous invocation make the overall work finish sooner?
    No — it only shortens the caller's wait. The function still takes the same time to run, and the event may sit briefly in Lambda's internal queue first, so end-to-end latency is usually slightly worse. What you gain is decoupling: the caller is not held hostage by the handler's duration or by a transient downstream failure.

saying these in an interview costs you the question

  • Thinks an Event invocation returns the function's return value
  • Assumes HTTP 200 from Invoke means the handler succeeded
  • Believes AWS retries every failed invocation regardless of type
  • Says asynchronous invocation makes the function itself run faster
  • Claims the AWS SDK retries application errors on synchronous invokes

context

open as a page

An AWS Lambda function invoked asynchronously (InvocationType Event) throws on every attempt. Describe what Lambda does with that event from the moment it accepts it until the event is gone for good.

level: middleimportance: must knowfreq 66%

basics

~20 s

Lambda queues the event, returns 202, then invokes the function. On failure it retries twice by default with delays of minutes, subject to a maximum event age of six hours. After that the event is discarded unless a failure destination or dead-letter queue captures it.

open as a page

For asynchronous AWS Lambda invocations, what is the difference between an on-failure destination and the older DeadLetterConfig dead-letter queue, and which should you configure on a new function?

level: middleimportance: should knowfreq 44%

basics

~20 s

A dead-letter queue receives only the original event payload and can target SQS or SNS. An on-failure destination receives a richer record with the invocation context and the error response, and can also target EventBridge or another Lambda function. Prefer destinations on new functions.

open as a page

An asynchronously invoked AWS Lambda function charges customers, and finance reports occasional double charges even though CloudWatch shows no function errors for those invocations. Explain how a Lambda invocation that succeeded can still run twice, and how you would stop the double charge.

level: seniorimportance: should knowfreq 52%

basics

~20 s

Asynchronous Lambda invocation is at-least-once: the internal queue can deliver the same event more than once even without a handler error, and a handler that completes its side effect but then times out is retried too. The fix is idempotency in the handler, not tighter retry settings.

open as a page

You are designing a workflow backed by AWS Lambda and must decide whether the caller retries a failed synchronous invoke, or the work is handed to Lambda's asynchronous invocation path so Lambda retries it. How do you make that call, and what does each choice cost you?

level: principalimportance: should knowfreq 38%

basics

~20 s

Decide by who must know the outcome and how long they can wait. Caller-side retry keeps the error visible and the policy yours, but multiplies in-flight load during an outage. Lambda-side asynchronous retry buys durability and backpressure at the cost of a coarse, untunable policy and no response channel.

open as a page

What is an AWS Lambda function URL, and when would you use one instead of putting API Gateway in front of the function?

level: middleimportance: nice to knowfreq 36%

basics

~20 s

A function URL is a built-in HTTPS endpoint on a single Lambda function, created with an auth type of NONE or AWS_IAM. It invokes the function synchronously with no extra service in the path. Choose it for simple single-function endpoints, webhooks and streamed responses.

open as a page