DEV Community

WonderfulSoap
WonderfulSoap

Posted on

Deep Dive into AWS Lambda (2): Lambda Bootstrap Exception Handling: Failure, Timeout Behavior Analysis, and Proper Handling

In the previous article, we discussed the AWS Lambda bootstrap and the Lambda Runtime API.

As the core of Lambda, after a Lambda instance starts up, it launches the bootstrap via /var/runtime/init. The bootstrap then communicates with the Lambda service through the Runtime API to retrieve and process user events.

Terminology note: AWS officially refers to this as an "execution environment" rather than an "instance." For consistency with the previous article, this article uses instance.

Based on the timing of the bootstrap's calls to the Lambda Runtime API, we can divide the bootstrap lifecycle into two phases:

  • Init Stage: The phase from when the bootstrap starts until it calls the /next API is the Init Stage.
  • Invocation Stage: The phase after the bootstrap calls the /next API, processes the user event, and finally calls the /response API is the Invocation Stage. The bootstrap processes user events and returns results to the Lambda service during this phase.

Although exception handling is often uninteresting, it is a key point for understanding the Lambda startup and execution flow — especially for a serverless model like Lambda.

For the two phases of the bootstrap, we need to focus on the following questions:

  • What happens if the bootstrap fails during the Init Stage? What about timeouts?
  • What happens if the bootstrap fails during the Invocation Stage? What about timeouts?
  • What happens if the bootstrap fails after calling the /response API but before the next call to the /next API? What about timeouts?

The following sequence diagram shows the specific stages and the exception handling for each stage that we will discuss.

Prerequisites

We continue using the test Lambda function created in the previous article for our tests.

This function uses:

  • Amazon Linux 2 runtime to facilitate our customization of the bootstrap
  • Since all parameters use default settings, the function timeout uses the default of 3 seconds
  • Additionally, we enabled Function URL in Configuration - Function URL - Create function URL to conveniently invoke the Lambda function directly via curl for testing user request behavior

At the same time, for Lambda, confirming whether a Lambda instance was newly started for handling a request is very important (after all, Lambda cold start is a critical performance metric). We also need to confirm whether Lambda starts a new instance after an exception occurs.
For Lambda, we can check whether a new instance was started by looking at the Log stream name in the corresponding function's CloudWatch Logs - Log groups.

As shown in the figure below, when Lambda starts a new instance, it creates a new Log stream. The name of this Log stream follows the format 202x/xx/xx/[$LATEST]xxxx. Logs from the same instance are recorded in the same Log stream.
Using this method, we can confirm whether each request triggers a new instance.

Init Stage Exceptions: Failures Before Calling the /next API

There are multiple scenarios for failures before calling the /next API (i.e., during the Init Stage). Let's discuss them separately.

Failure Due to Missing bootstrap

First, let's check the Lambda behavior when the bootstrap simply does not exist. Since Lambda does not allow uploading an empty zip package, we rename bootstrap to bootstrap2.

mv bootstrap bootstrap2
zip -r ../bootstrap-test.zip .
Enter fullscreen mode Exit fullscreen mode

Then update the Lambda function via the AWS Console, so we have constructed a Lambda function without a bootstrap.

Try using curl to call the previously created Function URL to test the behavior:

curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws -v
......
< HTTP/1.1 502 Bad Gateway
...
Internal Server Error%
......
Enter fullscreen mode Exit fullscreen mode

We got a 502 HTTP status code, and the response body is Internal Server Error, indicating that the Lambda service encountered an error while processing the request.

Note: Depending on how the Lambda function is invoked (e.g., via Function URL, API Gateway, or AWS SDK), these callers respond differently to Lambda errors. In this test, we use Function URL for testing.

Now let's examine the logs for this function invocation:

INIT_REPORT Init Duration: 0.35 ms  Phase: init Status: error   Error Type: Runtime.InvalidEntrypoint
INIT_REPORT Init Duration: 0.26 ms  Phase: invoke   Status: error   Error Type: Runtime.InvalidEntrypoint
START RequestId: d8c29a1c-cc6d-447b-899b-054777791892 Version: $LATEST
RequestId: d8c29a1c-cc6d-447b-899b-054777791892 Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]
Runtime.InvalidEntrypoint
END RequestId: d8c29a1c-cc6d-447b-899b-054777791892
REPORT RequestId: d8c29a1c-cc6d-447b-899b-054777791892  Duration: 42.44 ms  Billed Duration: 43 ms  Memory Size: 128 MB Max Memory Used: 3 MB
Enter fullscreen mode Exit fullscreen mode

The logs clearly show the Runtime.InvalidEntrypoint error, along with the detailed error message Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap].

When the bootstrap does not exist, Lambda will not attempt to restart the bootstrap (this differs from the other error scenarios we'll discuss later).

We then immediately invoke the Function URL again and observe the logs to determine whether Lambda starts a new instance to retry the bootstrap after the failure:

curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws -v
......
< HTTP/1.1 502 Bad Gateway
...
Internal Server Error%
......
Enter fullscreen mode Exit fullscreen mode

# Logs from the first request
...
START RequestId: d8c29a1c-cc6d-447b-899b-054777791892 Version: $LATEST
...
# Logs from the second request
...
START RequestId: 9c8b1a1c-cc6d-447b-899b-054777791892 Version: $LATEST
...
Enter fullscreen mode Exit fullscreen mode

We find that both requests' logs are recorded in the same Log Stream, which means Lambda did not start a new instance to handle the second request. Instead, it reused the instance from the first request.

Summary

When the bootstrap does not exist:

  1. Lambda returns 502 Internal Server Error to the user and logs a Runtime.InvalidEntrypoint error.
  2. Lambda does not attempt to restart the bootstrap.
  3. Lambda reuses the instance for subsequent requests instead of starting a new instance.

exit 0: Failure Due to Normal Exit

What happens if the bootstrap exits normally (i.e., exit 0) during the Init Stage? We modify the bootstrap content as shown below, where it outputs bootstrap is executed! and then exits normally:

#!/bin/sh
set -euo pipefail

echo "bootstrap is executed!"
exit 0
Enter fullscreen mode Exit fullscreen mode

Again, we use curl to call the Function URL to test the behavior:

curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws -v
Internal Server Error
Enter fullscreen mode Exit fullscreen mode

The curl response Internal Server Error is the same as when the bootstrap does not exist.

Now let's examine the logs:

08:48:32.246 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
08:48:32.254 bootstrap is executed!
08:48:32.255 INIT_REPORT Init Duration: 8.77 ms Phase: init Status: error Error Type: Runtime.ExitError
08:48:32.283 bootstrap is executed!
08:48:32.302 INIT_REPORT Init Duration: 28.52 ms Phase: invoke Status: error Error Type: Runtime.ExitError
08:48:32.302 START RequestId: 951da5f6-c388-43ac-8291-7e27d5b58de7 Version: $LATEST
08:48:32.362 RequestId: 951da5f6-c388-43ac-8291-7e27d5b58de7 Error: Runtime exited without providing a reason Runtime.ExitError
08:48:32.362 END RequestId: 951da5f6-c388-43ac-8291-7e27d5b58de7
08:48:32.362 REPORT RequestId: 951da5f6-c388-43ac-8291-7e27d5b58de7 Duration: 88.56 ms Billed Duration: 89 ms Memory Size: 128 MB Max Memory Used: 3 MB
Enter fullscreen mode Exit fullscreen mode

We find that after the bootstrap outputs bootstrap is executed! and exits, the Lambda service logs a Runtime.ExitError error. The logs also record Runtime exited without providing a reason.
Additionally, we notice that bootstrap is executed! appears twice in the logs, indicating that after the bootstrap exits, the Lambda service detects the exception and immediately retries by restarting the bootstrap to recover it.
After the restart also fails, the Lambda service gives up retrying and returns 502 Internal Server Error to the user.
Meanwhile, through testing (using the same verification method as before, which will be omitted hereafter), we find that after the bootstrap exits, Lambda does not start a new instance for subsequent requests.

Summary

When the bootstrap exits normally (exit 0) during the Init Stage:

  1. Lambda detects the bootstrap exit and logs a Runtime.ExitError error, then attempts to restart the bootstrap.
  2. If the bootstrap restart fails, the Lambda service gives up and returns 502 Internal Server Error to the user.
  3. Lambda does not start a new instance for subsequent requests but reuses the same instance.

exit 1: Failure Due to Abnormal Exit

When a program or script exits with a non-zero exit code, it typically indicates that an error or exception occurred during execution. This type of exit is called an "abnormal exit" or "error exit," which conveys to the operating system or the caller that the program failed to complete its intended task.

We modify the bootstrap script to test the Lambda behavior when the script exits with exit 1. As shown below, compared to the exit 0 case, we only change exit 0 to exit 1, keeping everything else the same.
same as exit 0

#!/bin/sh
set -euo pipefail

echo "bootstrap is executed!"
exit 1
Enter fullscreen mode Exit fullscreen mode

Invoke the Function URL to test the behavior:

curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error
Enter fullscreen mode Exit fullscreen mode

The returned error is the same as the exit 0 case — Internal Server Error. Now let's examine the corresponding logs:

08:46:54.784 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
08:46:54.798 bootstrap is executed!
08:46:54.798 INIT_REPORT Init Duration: 14.49 ms Phase: init Status: error Error Type: Runtime.ExitError
08:46:54.833 bootstrap is executed!
08:46:54.850 INIT_REPORT Init Duration: 31.73 ms Phase: invoke Status: error Error Type: Runtime.ExitError
08:46:54.851 START RequestId: b0897055-9b29-46d8-beda-61ef735a1b62 Version: $LATEST
08:46:54.872 RequestId: b0897055-9b29-46d8-beda-61ef735a1b62 Error: Runtime exited with error: exit status 1 Runtime.ExitError
08:46:54.872 END RequestId: b0897055-9b29-46d8-beda-61ef735a1b62
08:46:54.872 REPORT RequestId: b0897055-9b29-46d8-beda-61ef735a1b62 Duration: 53.08 ms Billed Duration: 54 ms Memory Size: 128 MB Max Memory Used: 3 MB
Enter fullscreen mode Exit fullscreen mode

We find that the behavior when the bootstrap exits with exit 1 is similar to the exit 0 case.

The Lambda service logs a Runtime.ExitError error and attempts to restart the bootstrap to recover it. If the restart fails, the Lambda service gives up and returns 502 Internal Server Error to the user.
The only difference is that the error detail in the logs changes from Runtime exited without providing a reason to Runtime exited with error: exit status 1, indicating that the Lambda service correctly captured the bootstrap's exit code and recorded it in the logs.

Does Lambda reuse the instance for subsequent requests in this case? After testing: yes, it does.

Summary

When the bootstrap exits with exit 1 during the Init Stage:

  1. The behavior is similar to exit 0.
  2. Lambda detects the bootstrap exit and logs a Runtime.ExitError error, then attempts to restart the bootstrap.
  3. If the bootstrap restart fails, the Lambda service gives up and returns 502 Internal Server Error to the user.
  4. Lambda does not start a new instance for subsequent requests but reuses the same instance.

Init Stage Exception: Timeout Before Calling the /next API

According to the official documentation Lambda Lifecycle, the bootstrap's Init Stage has a timeout limit (after all, if the Init Stage takes too long, it will significantly delay the response to the user).

The Init phase ends when the runtime and all extensions signal that they are ready by sending a Next API request. The Init phase is limited to 10 seconds. If all three tasks do not complete within 10 seconds, Lambda retries the Init phase at the time of the first function invocation with the configured function timeout.

According to the above description, the Init Stage timeout is 10 seconds. We modify the bootstrap to simulate a timeout during the Init Stage. As shown below, we have the bootstrap output bootstrap is executed! and then sleep for 15 seconds to simulate the timeout:

#!/bin/sh
set -euo pipefail

echo "bootstrap is executed! sleep 15s"
sleep 15
echo "bootstrap sleep done"
Enter fullscreen mode Exit fullscreen mode
time curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error curl   0.02s user 0.01s system 0% cpu 14.089 total
Enter fullscreen mode Exit fullscreen mode

It didn't take 10 seconds — it took about 14 seconds. After multiple attempts with the same request:

time curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error curl   0.03s user 0.00s system 1% cpu 2.985 total

time curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error curl   0.02s user 0.00s system 0% cpu 2.996 total
Enter fullscreen mode Exit fullscreen mode

We can observe that subsequent requests take about 3 seconds instead of 10. Let's retrieve the Lambda logs to see what happened.

Mapping each request to its corresponding logs:

First request
    ...
    12:34:35.598 bootstrap is executed! sleep 15s
    12:34:45.598 INIT_REPORT Init Duration: 10008.79 ms Phase: init Status: timeout
    12:34:45.626 bootstrap is executed! sleep 15s
    12:34:48.619 INIT_REPORT Init Duration: 3003.40 ms Phase: invoke Status: timeout
    12:34:48.625 2026-02-13T12:34:48.625Z 27e8b154-e141-4c3a-9dd8-6ed6592aa174 Task timed out after 3.01 seconds
    12:34:48.625 END RequestId: 27e8b154-e141-4c3a-9dd8-6ed6592aa174
    12:34:48.625 REPORT RequestId: 27e8b154-e141-4c3a-9dd8-6ed6592aa174 Duration: 3009.44 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 3 MB
    12:34:48.665 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
    12:34:48.667 bootstrap is executed! sleep 15s
    12:34:58.674 INIT_REPORT Init Duration: 10008.88 ms Phase: init Status: timeout

Second request
    12:35:34.615 bootstrap is executed! sleep 15s
    12:35:37.617 INIT_REPORT Init Duration: 3003.32 ms Phase: invoke Status: timeout
    12:35:37.617 START RequestId: 3990792c-3238-4ced-8acc-abda08dd8590 Version: $LATEST
    12:35:37.618 2026-02-13T12:35:37.618Z 3990792c-3238-4ced-8acc-abda08dd8590 Task timed out after 3.00 seconds
    12:35:37.618 END RequestId: 3990792c-3238-4ced-8acc-abda08dd8590
    12:35:37.618 REPORT RequestId: 3990792c-3238-4ced-8acc-abda08dd8590 Duration: 3004.50 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 3 MB
    12:35:37.642 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
    12:35:37.644 bootstrap is executed! sleep 15s
    12:35:47.651 INIT_REPORT Init Duration: 10008.73 ms Phase: init Status: timeout

Third request
    12:36:49.102 bootstrap is executed! sleep 15s
    12:36:52.104 INIT_REPORT Init Duration: 3003.25 ms Phase: invoke Status: timeout
    12:36:52.104 START RequestId: a0a3b004-be56-4db3-bb97-0721aac10563 Version: $LATEST
    12:36:52.105 2026-02-13T12:36:52.104Z a0a3b004-be56-4db3-bb97-0721aac10563 Task timed out after 3.00 seconds
    12:36:52.105 END RequestId: a0a3b004-be56-4db3-bb97-0721aac10563
    12:36:52.105 REPORT RequestId: a0a3b004-be56-4db3-bb97-0721aac10563 Duration: 3004.30 ms Billed Duration: 3000 ms Memory Size: 128 MB Max Memory Used: 3 MB
    12:36:52.124 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
    12:36:52.126 bootstrap is executed! sleep 15s
    12:37:02.133 INIT_REPORT Init Duration: 10008.89 ms Phase: init Status: timeout
Enter fullscreen mode Exit fullscreen mode
  • A bootstrap execution timeout does not trigger a new instance launch. Instead, the same instance is reused and the bootstrap is re-invoked on the next request.
  • For the first request (i.e., the first time the instance starts):
    • After the bootstrap times out at 10 seconds, the Lambda service retries by invoking the bootstrap again. However, the timeout for the second attempt is not 10 seconds but 3 seconds instead.
    • After the second attempt (3 seconds) times out, the Lambda service immediately returns 502 Internal Server Error to the caller.
    • However, if we look closely at the logs, we notice that after the second timeout, Lambda actually makes a third attempt to invoke the bootstrap, this time with a 10-second timeout, after which no more retries are made. Importantly, this third attempt occurs after Lambda has already returned the 502 to the user. This means the third attempt is Lambda trying to restore the instance to a normal state so it can accept the next user request.
  • For the second request:
    • When the second request comes in, Lambda again attempts to restart the bootstrap, this time with only a 3-second timeout. If it times out again, Lambda directly returns 502 Internal Server Error to the user without further retries.
    • Similarly, after returning 502, Lambda also attempts to invoke the bootstrap again to restore the instance. This time the timeout is 10 seconds.
  • The third request behaves the same as the second request.

We then noticed that the 3-second timeout seems to be related to the Lambda function's configured timeout. After changing the Lambda function's timeout to 30 seconds and invoking the function again, let's observe the logs:

/* First request */ API request took 25s
    10:08:25.818 bootstrap is executed! sleep 15s
    10:08:35.805 INIT_REPORT Init Duration: 9994.77 ms Phase: init Status: timeout
    10:08:35.837 bootstrap is executed! sleep 15s
    10:08:50.839 bootstrap sleep done
    10:08:50.839 INIT_REPORT Init Duration: 15016.29 ms Phase: invoke Status: error Error Type: Runtime.ExitError
    10:08:50.839 START RequestId: d7501337-05f2-4bd9-be07-e5d611a4b3c7 Version: $LATEST
    10:08:50.856 RequestId: d7501337-05f2-4bd9-be07-e5d611a4b3c7 Error: Runtime exited without providing a reason Runtime.ExitError
    10:08:50.856 END RequestId: d7501337-05f2-4bd9-be07-e5d611a4b3c7
    10:08:50.856 REPORT RequestId: d7501337-05f2-4bd9-be07-e5d611a4b3c7 Duration: 15033.66 ms Billed Duration: 15034 ms Memory Size: 128 MB Max Memory Used: 3 MB
    10:08:50.901 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
    10:08:50.903 bootstrap is executed! sleep 15s
    10:09:00.898 INIT_REPORT Init Duration: 9997.18 ms Phase: init Status: timeout

/* Second request */
    10:09:42.356 bootstrap is executed! sleep 15s
    10:09:57.357 bootstrap sleep done
    10:09:57.358 INIT_REPORT Init Duration: 15011.50 ms Phase: invoke Status: error Error Type: Runtime.ExitError
    10:09:57.358 START RequestId: c6760830-db1d-431c-9948-8b822d4958e6 Version: $LATEST
    10:09:57.359 RequestId: c6760830-db1d-431c-9948-8b822d4958e6 Error: Runtime exited without providing a reason Runtime.ExitError
    10:09:57.359 END RequestId: c6760830-db1d-431c-9948-8b822d4958e6
    10:09:57.359 REPORT RequestId: c6760830-db1d-431c-9948-8b822d4958e6 Duration: 15012.88 ms Billed Duration: 15013 ms Memory Size: 128 MB Max Memory Used: 3 MB
    10:09:57.392 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
    10:09:57.394 bootstrap is executed! sleep 15s
    10:10:07.392 INIT_REPORT Init Duration: 9999.78 ms Phase: init Status: timeout
Enter fullscreen mode Exit fullscreen mode

As we suspected, the second timeout is indeed the Lambda function's configured timeout. Let's summarize again:

  • After starting the bootstrap, there is a 10-second timeout before calling the /next API. If this time is exceeded, the Lambda service terminates the bootstrap and restarts it.
  • The timeout for the second bootstrap startup is the Lambda function's configured timeout.
  • If the second bootstrap startup still fails (or times out), the Lambda service immediately returns 502 Internal Server Error to the user.
  • Then the Lambda service makes a third attempt to restart the bootstrap, this time with the timeout reverting to 10 seconds. The purpose of this third attempt is to restore the instance to a normal state so it can accept the next user request.

Summary

  • After starting the bootstrap, there is a 10-second timeout before calling the /next API. If this time is exceeded, the Lambda service terminates the bootstrap and restarts it.
  • The timeout for the second bootstrap startup is the Lambda function's configured timeout.
  • If the second bootstrap startup still fails (or times out), the Lambda service immediately returns 502 Internal Server Error to the user.
  • Then the Lambda service makes a third attempt to restart the bootstrap, this time with the timeout reverting to 10 seconds. The purpose of this third attempt is to restore the instance to a normal state so it can accept the next user request.

Properly Handling Init Stage Exceptions

Above we tested the Lambda behavior when the bootstrap encounters exceptions during the Init Stage. Now let's discuss how to properly handle exceptions when the bootstrap fails during the Init Stage.

According to the AWS Lambda Runtime API documentation, when the bootstrap encounters an exception during the Init Stage, it should call the /init/error API to notify the Lambda service.

This API, like the /next and /response APIs mentioned in the previous article, is part of the Runtime API. We call this API to notify the Lambda service that the bootstrap encountered an exception during the Init Stage.

Key points for calling this API:

  • The request URL is http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/init/error
  • It uses a POST request
  • The request header must include the Lambda-Runtime-Function-Error-Type field, which is a user-customizable string that describes the error type. This field is captured by the Lambda service and recorded in the logs.
  • Upon success, this API returns a 202 status code with the response body {"status":"OK"}, indicating that the Lambda service has successfully received the error information and logged it.
  • The request payload is a JSON object with the following structure:
    • errorMessage: An error message string describing the error details
    • errorType: An error type string describing the error type, customizable
    • stackTrace: Error stack trace information, typically an array of strings describing the call stack at the time of the error
{
      "errorMessage" : "Error parsing event data.",
      "errorType" : "InvalidEventDataException",
      "stackTrace": [ ]
}
Enter fullscreen mode Exit fullscreen mode

Next, we modify the bootstrap to simulate a scenario where the bootstrap encounters an exception that is caught within the script. We then call the /init/error API within the script to notify the Lambda service, and output the API's Response Body:

#!/bin/sh
set -eu
echo "bootstrap is executed!"

# simulate an error caught in the bootstrap path, then notify Lambda by calling /init/error API
RESP="$(curl -sS -w "\nHTTP %{http_code}\n" \
  -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/init/error" \
  -H "Content-Type: application/json" \
  -H "Lambda-Runtime-Function-Error-Type: Bootstrap.Unhandled" \
  -d '{"errorMessage":"Failed to load function.","errorType":"InvalidFunctionException","stackTrace":[]}')"

echo "$RESP"
exit 1
Enter fullscreen mode Exit fullscreen mode

As before, we use curl to call the Function URL to test the behavior:

curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error
Enter fullscreen mode Exit fullscreen mode

We find that the caller's error is the same as the previous exit 1 case — Internal Server Error. Now let's examine the relevant logs:

09:43:09.214 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
09:43:09.224 bootstrap is executed!
09:43:09.245 {"status":"OK"}
09:43:09.245 HTTP 202
09:43:09.246 INIT_REPORT Init Duration: 32.18 ms Phase: init Status: error Error Type: Runtime.Unknown
09:43:09.268 bootstrap is executed!
09:43:09.449 {"status":"OK"}
09:43:09.449 HTTP 202
09:43:09.469 INIT_REPORT Init Duration: 203.92 ms Phase: invoke Status: error Error Type: Runtime.Unknown
09:43:09.469 START RequestId: 1ae2f688-f2e8-4739-aa18-1fc4703e3647 Version: $LATEST
09:43:09.470 Unknown application error occurred Runtime.Unknown
09:43:09.470 END RequestId: 1ae2f688-f2e8-4739-aa18-1fc4703e3647
09:43:09.470 REPORT RequestId: 1ae2f688-f2e8-4739-aa18-1fc4703e3647 Duration: 204.69 ms Billed Duration: 205 ms Memory Size: 128 MB Max Memory Used: 5 MB
Enter fullscreen mode Exit fullscreen mode

We find that the behavior is similar to the exit 1 case — Lambda attempts to restart the bootstrap to recover it, and if the restart fails, the Lambda service gives up and returns 502 Internal Server Error to the user.
However, the error type Bootstrap.Unhandled that we set via the /init/error API was not recorded in the logs. The logs only show a Runtime.Unknown error type.

At this point, you might wonder: since the behavior is the same as directly exiting the bootstrap, what is the purpose of calling the /init/error API?

Next, let's correct the bootstrap by having it attempt to call the /next API to retrieve events after calling the /init/error API:

#!/bin/sh
set -eu
echo "bootstrap is executed!"

# simulate an error caught in the bootstrap path, then notify Lambda by calling /init/error API
RESP="$(curl -sS -w "\nHTTP %{http_code}\n" \
  -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/init/error" \
  -H "Content-Type: application/json" \
  -H "Lambda-Runtime-Function-Error-Type: Bootstrap.Unhandled" \
  -d '{"errorMessage":"Failed to load function.","errorType":"InvalidFunctionException","stackTrace":[]}')"

echo "$RESP"

# call /next API after sending error report to Lambda service
RESPONSE=$(curl -s "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
echo "The event data is: $RESPONSE"

exit 1
Enter fullscreen mode Exit fullscreen mode

Observe the corresponding logs:

09:43:43.046 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
09:43:43.055 bootstrap is executed!
09:43:43.079 {"status":"OK"}
09:43:43.079 HTTP 202
09:43:43.085 The event data is: {"errorMessage":"State transition from InitError to Ready failed for runtime. Error: State transition is not allowed","errorType":"InvalidStateTransition"}
09:43:43.086 INIT_REPORT Init Duration: 39.37 ms Phase: init Status: error Error Type: Runtime.Unknown
09:43:43.110 bootstrap is executed!
09:43:43.275 {"status":"OK"}
09:43:43.275 HTTP 202
09:43:43.455 The event data is: {"errorMessage":"State transition from InitError to Ready failed for runtime. Error: State transition is not allowed","errorType":"InvalidStateTransition"}
09:43:43.456 INIT_REPORT Init Duration: 348.23 ms Phase: invoke Status: error Error Type: Runtime.Unknown
09:43:43.456 START RequestId: 762dc5ad-e25a-4829-b4bc-39668836b404 Version: $LATEST
09:43:43.478 Unknown application error occurred Runtime.Unknown
09:43:43.478 END RequestId: 762dc5ad-e25a-4829-b4bc-39668836b404
09:43:43.478 REPORT RequestId: 762dc5ad-e25a-4829-b4bc-39668836b404 Duration: 368.36 ms Billed Duration: 369 ms Memory Size: 128 MB Max Memory Used: 5 MB
Enter fullscreen mode Exit fullscreen mode

We find that after reporting the init error to the Lambda service and then attempting to call the /next API, the following error is returned: State transition from InitError to Ready failed for runtime. Error: State transition is not allowed

This shows that after calling the /init/error API, Lambda marks this instance as being in an error state and refuses to let the bootstrap retrieve user events.

This is actually consistent with the recommended bootstrap initialization error handling approach in the official documentation:

Handle errors – If an error occurs, call the initialization error API and exit immediately.

An Init Stage error means this instance cannot function properly, so after reporting the error, Lambda refuses to provide event data, and the bootstrap exits.

Summary

When the bootstrap encounters an exception during the Init Stage, the proper handling approach is to call the /init/error API to notify the Lambda service, and then exit the bootstrap.

Invocation Stage Exceptions: Failures After Calling the /next API but Before Returning the /response API

The phase after calling the /next API and before returning the /response API is the Invocation Stage. This phase is essentially when our handler code runs during normal Lambda usage.

Exception handling during this phase is of great concern to us, as exceptions in this phase directly affect the execution of our handler code.

Let's discuss the exception handling for various scenarios.

Bootstrap Crash Exit

We modify the bootstrap code to make it exit after requesting the /next API and retrieving the user request event:

#!/bin/sh
set -euo pipefail
echo "bootstrap is executed!"

RESPONSE=$(curl -s "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
echo "The event data is: $RESPONSE"
exit 1
Enter fullscreen mode Exit fullscreen mode

We try invoking the function twice:

time curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error curl   0.05s user 0.03s system 27% cpu 0.287 total

time curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error curl   0.03s user 0.01s system 27% cpu 0.131 total
Enter fullscreen mode Exit fullscreen mode

As before, both requests return 502 Internal Server Error. The key is to examine the Lambda logs to observe the behavior.
Logs:

/*First request*/
13:18:48.164 bootstrap is executed!
13:18:48.182 START RequestId: 0a0faefe-ec5e-49e0-9aaa-c4b0942ebe8d Version: $LATEST
13:18:48.183 The event data is: xxxxxxx
13:18:48.196 RequestId: 0a0faefe-ec5e-49e0-9aaa-c4b0942ebe8d Error: Runtime exited with error: exit status 1 Runtime.ExitError
13:18:48.196 END RequestId: 0a0faefe-ec5e-49e0-9aaa-c4b0942ebe8d
13:18:48.196 REPORT RequestId: 0a0faefe-ec5e-49e0-9aaa-c4b0942ebe8d Duration: 14.51 ms Billed Duration: 39 ms Memory Size: 128 MB Max Memory Used: 25 MB Init Duration: 24.06 ms
13:18:48.217 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
13:18:48.219 bootstrap is executed!

/*Second request*/
13:20:07.256 START RequestId: a2ff7278-f98c-4c8c-b837-7e1eb407db25 Version: $LATEST
13:20:07.257 The event data is: xxxxxx
13:20:07.276 RequestId: a2ff7278-f98c-4c8c-b837-7e1eb407db25 Error: Runtime exited with error: exit status 1 Runtime.ExitError
13:20:07.276 END RequestId: a2ff7278-f98c-4c8c-b837-7e1eb407db25
13:20:07.276 REPORT RequestId: a2ff7278-f98c-4c8c-b837-7e1eb407db25 Duration: 20.89 ms Billed Duration: 21 ms Memory Size: 128 MB Max Memory Used: 4 MB
13:20:07.312 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
13:20:07.313 bootstrap is executed!
Enter fullscreen mode Exit fullscreen mode

Examining the logs above, we find that when the bootstrap abnormally exits during the Invocation Stage, the following behavior occurs:

  • Lambda outputs the error log Runtime exited with error: exit status 1 Runtime.ExitError and immediately returns 502 Internal Server Error to the user.
  • Lambda then attempts to restart the bootstrap, at which point the bootstrap calls the /next API again. Since the previous user request event has already been returned to the user, this /next API call blocks, waiting for the next user request to arrive.
  • When a new user request comes in, Lambda normally passes the user event to /next to unblock it, and the bootstrap continues executing subsequent logic, repeating the cycle.

Summary

If the bootstrap crashes during the Invocation Stage, Lambda immediately returns 502 Internal Server Error to the user and then attempts to restart the bootstrap. The bootstrap will call the /next API again. Since the previous user request event has already been returned to the user, this /next API call blocks, waiting for the next user request to arrive.

Bootstrap Processing Timeout

The Invocation Stage timeout is probably one of the most familiar Lambda features. In the prerequisites section of this article, we mentioned that our example Lambda function uses the default timeout of 3 seconds — this 3 seconds refers to the Invocation Stage timeout.

Generally, our understanding of this Lambda timeout is:

The timeout for handler code processing

But in reality, the essence of this timeout is:

The timeout from when the bootstrap calls the /next API until it returns the /response API

We modify the bootstrap code to have it sleep for 10 seconds after calling the /next API to simulate an Invocation Stage timeout:

#!/bin/sh
set -euo pipefail
echo "bootstrap is executed!"

# request /next api
HEADERS_FILE=$(mktemp)
RESPONSE=$(curl -sS -D "$HEADERS_FILE" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS_FILE" | tr -d '[:cntrl:]' | awk '{print $2}')
echo "The event data is: $RESPONSE"
echo "The Request ID is: $REQUEST_ID"

# Sleep 10s to make lambda invocation stage timeout
sleep 10s

LAMBDA_RESPONSE="{\"message\": \"Hello from bootstrap!\", \"echo\": $RESPONSE}"
curl -s -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$LAMBDA_RESPONSE"

echo "Response sent successfully!"
Enter fullscreen mode Exit fullscreen mode

Invoke this Lambda function via curl:

time curl https://gpwttqecuedsmpnefqmotkx7dy0uhydr.lambda-url.ap-northeast-1.on.aws/
Internal Server Error curl   0.03s user 0.01s system 1% cpu 3.140 total
Enter fullscreen mode Exit fullscreen mode

We find that the result is as expected:

  • The function invocation resulted in an error, returning 502 Internal Server Error
  • The total invocation time was 3.140s, consistent with our configured timeout of 3 seconds, meaning the bootstrap's 10-second sleep correctly triggered the Invocation Stage timeout

Now let's focus on the Lambda logs:

...
14:28:28.951 bootstrap is executed!
14:28:29.044 The event data is: xxxx
14:28:29.044 The Request ID is: 2703bbf7-5dfa-40e5-98bb-fdb55f6750c4
14:28:31.977 2026-02-13T14:28:31.977Z 2703bbf7-5dfa-40e5-98bb-fdb55f6750c4 Task timed out after 3.00 seconds
...
14:28:32.007 bootstrap is executed!
Enter fullscreen mode Exit fullscreen mode

We can see that 3 seconds after the bootstrap started and retrieved the event from the /next API, the 3-second timeout error was triggered. The logs show the error Task timed out after 3.00 seconds.
After the timeout is triggered, Lambda immediately returns 502 Internal Server Error to the user.
Lambda then forcefully terminates and restarts the bootstrap, as evidenced by the 14:28:32.007 bootstrap is executed! log entry.
This shows that when the /response API call times out, Lambda restarts the bootstrap so it can call the /next API again and enter a blocking state, waiting for the next user request.

Summary

If the bootstrap times out during the Invocation Stage, Lambda immediately returns 502 Internal Server Error to the user, then terminates and restarts the bootstrap.
After the restart, the bootstrap calls the /next API again. Since the previous user request event has already been returned to the user, this /next API call blocks, waiting for the next user request to arrive.

Calling the /next API Again Immediately After Calling /next

Next, let's consider a special scenario: after the bootstrap retrieves the user request event by calling the /next API, instead of calling the /response API, it attempts to call the /next API multiple times to retrieve user request events.

What will the bootstrap's behavior be in this case?

#!/bin/sh
set -euo pipefail

echo "bootstrap is executed!"
echo "Call /next API for the first time"

HEADERS_FILE=$(mktemp)
RESPONSE=$(curl -sS -D "$HEADERS_FILE" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
# Get request id from next API header
REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS_FILE" | tr -d '[:cntrl:]' | awk '{print $2}')

echo "The event data is: $RESPONSE"
echo "The Request ID is: $REQUEST_ID"

echo "Call /next API for the second time"
HEADERS_FILE=$(mktemp)
RESPONSE=$(curl -sS -D "$HEADERS_FILE" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
# Get request id from next API header
REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS_FILE" | tr -d '[:cntrl:]' | awk '{print $2}')

echo "The event data is: $RESPONSE"
echo "The Request ID is: $REQUEST_ID"

echo "Call /next API for the second time"
HEADERS_FILE=$(mktemp)
RESPONSE=$(curl -sS -D "$HEADERS_FILE" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
# Get request id from next API header
REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS_FILE" | tr -d '[:cntrl:]' | awk '{print $2}')

echo "The event data is: $RESPONSE"
echo "The Request ID is: $REQUEST_ID"
Enter fullscreen mode Exit fullscreen mode

Running the Lambda function with the above code produces the following logs:

08:53:55.145 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
08:53:55.153 bootstrap is executed!
08:53:55.153 Call /next API for the first time
08:53:55.177 START RequestId: 60fa77a3-8a4c-439b-9121-3a210c52df18 Version: $LATEST
08:53:55.258 The event data is: xxx
08:53:55.258 The Request ID is: 60fa77a3-8a4c-439b-9121-3a210c52df18
08:53:55.258 Call /next API for the second time
08:53:55.458 The event data is: xxx
08:53:55.458 The Request ID is: 60fa77a3-8a4c-439b-9121-3a210c52df18
08:53:55.458 Call /next API for the second time
08:53:55.637 The event data is: xxx
08:53:55.637 The Request ID is: 60fa77a3-8a4c-439b-9121-3a210c52df18
08:53:55.640 RequestId: 60fa77a3-8a4c-439b-9121-3a210c52df18 Error: Runtime exited without providing a reason Runtime.ExitError
08:53:55.640 END RequestId: 60fa77a3-8a4c-439b-9121-3a210c52df18
08:53:55.640 REPORT RequestId: 60fa77a3-8a4c-439b-9121-3a210c52df18 Duration: 462.74 ms Billed Duration: 495 ms Memory Size: 128 MB Max Memory Used: 27 MB Init Duration: 31.65 ms
Enter fullscreen mode Exit fullscreen mode

We find that calling the /next API again immediately after the initial call does not block. Instead, it returns the same user event data and request ID as before.

This mechanism means that Lambda event processing requires calling the /response API (or exception handling) as the termination signal. Until then, Lambda keeps returning the same event data to the bootstrap, until the bootstrap calls the /response API or exception handling terminates the process.

Conclusion

We find that calling the /next API again immediately after the initial call does not block. Instead, it returns the same user event data and request ID. This means the Lambda event is bound to the instance — until the /response API is called to return a response, or the bootstrap is restarted due to processing timeout or other reasons, calling /next multiple times returns the same event data and request ID without blocking.

Properly Handling Invocation Stage Errors in the Bootstrap

Similar to Init Stage error handling, the Invocation Stage also has a corresponding Runtime API for reporting processing failures to Lambda: the invocation error API.

The bootstrap can call this API to notify the Lambda service when an error occurs while processing a user request event.

However, unlike Init Stage errors, after calling the /runtime/invocation/next API, your bootstrap should not exit but instead continue running and call /next to wait for the next event.

This makes logical sense. An Init Stage error means the bootstrap cannot function at all, so exiting directly is the recommended approach. An Invocation Stage error only means an error occurred while processing user request data (such as an RDS error, external request failure, or other business logic errors) — it does not affect the bootstrap itself. Therefore, when an Invocation Stage error occurs, the bootstrap does not need to exit. Instead, it should call the /next API to get the next event and continue processing.

Below is an example simulating Invocation Stage error handling. We use a complete while loop for event processing, and after calling the /next API, we directly call the /invocation/error API to notify the Lambda service that this event processing has failed.

After notifying Lambda, the bootstrap continues running and calls the /next API to wait for the next event.

Note: The specific path of the invocation error API is http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/${REQUEST_ID}/error. We need to specify the request-id of the failed request in the URL path. This ID is obtained from the /next API's response header Lambda-Runtime-Aws-Request-Id.

#!/bin/sh
set -euo pipefail
echo "bootstrap is executed!"

HEADERS_FILE=$(mktemp)

while true; do
  echo "start to call /next api..."
  RESPONSE=$(curl -sS -D "$HEADERS_FILE" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
  # Get request id from next API header
  REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS_FILE" | tr -d '[:cntrl:]' | awk '{print $2}')

  echo "The event data is: $RESPONSE"
  echo "The Request ID is: $REQUEST_ID"

  # simulate an error occurred when processing the event
  ERROR_JSON='{"errorMessage":"Error parsing event data.","errorType":"InvalidEventDataException","stackTrace":[]}'
  RESP=$(curl -sS -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/error" \
  -H "Content-Type: application/json" \
  -H "Lambda-Runtime-Function-Error-Type: Unhandled" \
  -d "$ERROR_JSON")

  echo "Invocation error API response: $RESP"
done
Enter fullscreen mode Exit fullscreen mode

Invoke this Lambda function:

curl https://xxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws
Internal Server Error curl   0.04s user 0.01s system 12% cpu 0.407 total
Enter fullscreen mode Exit fullscreen mode

The function's return result is still 502 Internal Server Error. Let's observe what's different in the logs:

09:49:58.061 bootstrap is executed!
09:49:58.063 start to call /next api...
09:49:58.164 The event data is: xxxxxxxxxx
09:49:58.164 The Request ID is: 0311825c-6689-46e7-a57d-6e3fc3b15ac8
09:49:58.285 Invocation error API response: {"status":"OK"}
09:49:58.285 start to call /next api...
09:49:58.367 END RequestId: 0311825c-6689-46e7-a57d-6e3fc3b15ac8
09:49:58.367 REPORT RequestId: 0311825c-6689-46e7-a57d-6e3fc3b15ac8 Duration: 283.82 ms Billed Duration: 314 ms Memory Size: 128 MB Max Memory Used: 27 MB Init Duration: 29.65 ms
Enter fullscreen mode Exit fullscreen mode

From our observations:

  • If the /invocation/error API call succeeds, its return value is {"status":"OK"}
  • After a successful /invocation/error API call, the logs do not show runtime crash errors
  • After sending the error information to the Lambda service, the bootstrap continues to call the /next API. Since there are no new user requests, the /next API blocks until the next user request arrives.

Conclusion

The proper way to handle Invocation Stage errors is to call the /invocation/error API to notify the Lambda service, and then instead of exiting the bootstrap, continue running and wait for the next event.
If the /invocation/error API call succeeds, its return value is {"status":"OK"}, and Lambda does not log runtime crash errors.

After Invocation Stage Exceptions: Failures After Calling the /response API but Before the Next /next API Call

There is one more special phase to consider: what happens if our bootstrap encounters an error after calling the /response API but before the next call to the /next API?

We refer to errors in this phase as After Invocation Stage errors.

Bootstrap Crash Exit

Similarly, we modify the bootstrap code to have it exit directly with exit 1 after calling the /response API:

#!/bin/sh
set -euo pipefail

echo "bootstrap is executed!"

HEADERS_FILE=$(mktemp)

while true; do
  echo "now to call /next API"
  RESPONSE=$(curl -sS -D "$HEADERS_FILE" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
  # Get request id from next API header
  REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS_FILE" | tr -d '[:cntrl:]' | awk '{print $2}')

  echo "The event data is: $RESPONSE"
  echo "The Request ID is: $REQUEST_ID"

  LAMBDA_RESPONSE="{\"message\": \"Hello from bootstrap!\", \"echo\": $RESPONSE}"
  curl -s -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$LAMBDA_RESPONSE"

  echo "Response sent successfully!"
  exit 1
done
Enter fullscreen mode Exit fullscreen mode

Try invoking the Lambda function:

time curl https://gpwttqecuedsmpnefqmotkx7dy0uhydr.lambda-url.ap-northeast-1.on.aws/
{"echo":{"headers":{"x-amzn-tls-cipher-suite":"TLS_AES_128_GCM_SHA.................}
curl   0.02s user 0.02s system 9% cpu 0.482 total
Enter fullscreen mode Exit fullscreen mode

This time the function invocation succeeded. The reason is simple: since the /response API was correctly called, the request processing completed successfully.

However, the Lambda bootstrap crashed after calling the /response API. Let's observe the logs to see the specific behavior:

09:54:39.254 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
09:54:39.262 bootstrap is executed!
09:54:39.292 START RequestId: 1fb629bd-eb19-42c5-8866-145fa8b5e2d3 Version: $LATEST
09:54:39.373 The event data is: xxxxxxxxx
09:54:39.373 The Request ID is: 1fb629bd-eb19-42c5-8866-145fa8b5e2d3
09:54:39.472 {"status":"OK"}
09:54:39.473 Response sent successfully!, now to exit bootstrap
09:54:39.475 RequestId: 1fb629bd-eb19-42c5-8866-145fa8b5e2d3 Error: Runtime exited with error: exit status 1 Runtime.ExitError
09:54:39.475 END RequestId: 1fb629bd-eb19-42c5-8866-145fa8b5e2d3
09:54:39.475 REPORT RequestId: 1fb629bd-eb19-42c5-8866-145fa8b5e2d3 Duration: 183.01 ms Billed Duration: 221 ms Memory Size: 128 MB Max Memory Used: 27 MB Init Duration: 37.42 ms
09:54:39.513 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
09:54:39.516 bootstrap is executed!
Enter fullscreen mode Exit fullscreen mode

As we can see, Lambda correctly received the response sent by the bootstrap via the /response API and returned the result to the user. However, since the bootstrap crashed afterward, Lambda logged the Runtime.ExitError error and then attempted to restart the bootstrap.

Summary

If the bootstrap crashes during the After Invocation Stage:

  • Since the /response API was correctly called, Lambda correctly returns the result to the user.
  • Lambda logs the Runtime.ExitError error and then restarts the bootstrap.

Bootstrap Processing Timeout

After returning the /response API but before the next call to the /next API, what happens if the bootstrap times out? And what exactly is this timeout duration?
We modify the bootstrap code to have it sleep for 15 seconds after calling the /response API to simulate a timeout:

#!/bin/sh
set -euo pipefail

echo "bootstrap is executed!"

HEADERS_FILE=$(mktemp)

while true; do
  echo "now to call /next API"
  RESPONSE=$(curl -sS -D "$HEADERS_FILE" "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next")
  # Get request id from next API header
  REQUEST_ID=$(grep -Fi Lambda-Runtime-Aws-Request-Id "$HEADERS_FILE" | tr -d '[:cntrl:]' | awk '{print $2}')

  echo "The event data is: $RESPONSE"
  echo "The Request ID is: $REQUEST_ID"

  LAMBDA_RESPONSE="{\"message\": \"Hello from bootstrap!\", \"echo\": $RESPONSE}"
  curl -s -X POST "http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/$REQUEST_ID/response" -d "$LAMBDA_RESPONSE"

  echo "Response sent successfully!, now to sleep 15s"
  sleep 15
  echo "sleep 15s over"
done
Enter fullscreen mode Exit fullscreen mode

Try invoking the Lambda function:

time curl https://gpwttqecuedsmpnefqmotkx7dy0uhydr.lambda-url.ap-northeast-1.on.aws/
{"echo":{"headers":{"x-amzn-tls-cipher-suite":"TLS_AES_128_GCM_SHA.................}
curl   0.02s user 0.02s system 9% cpu 0.482 total
Enter fullscreen mode Exit fullscreen mode

Since the /response API was correctly called, Lambda correctly returns the result to the user — this is consistent with our previous analysis.

Now let's observe the corresponding logs to see what happens afterward:

......
09:59:35.749 bootstrap is executed!
09:59:35.749 now to call /next API
......
09:59:35.971 Response sent successfully!, now to sleep 15s
09:59:38.776 2026-02-14T09:59:38.776Z da9ab253-01f9-42e6-aabe-c3d94374b20f Task timed out after 3.00 seconds
09:59:38.776 END RequestId: da9ab253-01f9-42e6-aabe-c3d94374b20f
09:59:38.776 REPORT RequestId: da9ab253-01f9-42e6-aabe-c3d94374b20f Duration: 3004.24 ms Billed Duration: 3033 ms Memory Size: 128 MB Max Memory Used: 27 MB Init Duration: 32.33 ms
09:59:38.848 INIT_START Runtime Version: provided:al2.v143 Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:64c84fb4abae0287749677ef42dbfb9c0b2bf4a3c7b1a638630bccc30cf04c7b
09:59:38.851 bootstrap is executed!
Enter fullscreen mode Exit fullscreen mode

We observe:

09:59:38.776 2026-02-14T09:59:38.776Z da9ab253-01f9-42e6-aabe-c3d94374b20f Task timed out after 3.00 seconds
Enter fullscreen mode Exit fullscreen mode

This shows that the timeout in this phase is controlled by the Lambda function's configured timeout. To verify this hypothesis, we changed the function's timeout to 30 seconds in the AWS Console and tried the request again. This time the logs show:

......
10:04:08.780 Response sent successfully!, now to sleep 15s
10:04:23.802 sleep 15s over
10:04:23.802 now to call /next API
......
Enter fullscreen mode Exit fullscreen mode

As we can see, after changing the Lambda function's timeout to 30 seconds, the bootstrap no longer times out. After completing the 15-second sleep, the bootstrap successfully calls the next /next API.

Summary

If the bootstrap times out during the After Invocation Stage:

  • The timeout duration is controlled by the Lambda function's configured timeout.
  • If it times out, Lambda logs a Task timed out after message and then restarts the bootstrap.
  • If it doesn't time out, Lambda continues executing the bootstrap to wait for the next user request.

Conclusion

At this point, we have completed our analysis of Lambda bootstrap exception handling, and it has indeed been a long and tedious process.
However, this is crucial for thoroughly understanding Lambda's execution flow and mechanisms, and it provides important guidance for customizing our own Lambda Runtime in the future.
After concluding this article and understanding the most fundamental Lambda Runtime API and bootstrap mechanisms, we will move on to more practical and interesting topics:

  • Analyzing the implementation of official Lambda Runtimes
  • How the handler we define in Lambda settings (e.g., index.handler) actually establishes a connection with the corresponding file and function
  • How the Handler Wrapper mechanism is implemented
  • And more

Top comments (0)