What it means
The provided runtimes — used by Go, Rust, C++ and anything else without a managed Lambda runtime — work on a simple contract. Lambda does not know how to start your language; it just executes a file called bootstrap and expects that program to talk to the Runtime API itself. When there is no such file it can run, initialisation fails before your code exists.
The message is unusually forthcoming. It lists the two paths Lambda searched, in the order it searched them: /var/task/bootstrap, which is your deployment package, and /opt/bootstrap, which is a layer. If your bootstrap is somewhere else, it is somewhere Lambda was never going to look.
The word doing the most work is valid. Lambda is not reporting that the file is absent; it is reporting that it found nothing it could execute. A bootstrap sitting right there in the archive fails this check when it is not marked executable, or when it was compiled for a different architecture than the function is configured for. The message is identical in all three cases, which is why "but the file is right there" is such a common reaction to it.
The executable bit is the cause worth suspecting first, because it is invisible in most of the ways people inspect a package. A unzip -l shows the file. A directory listing shows the file. Only the mode bits distinguish a working deployment from this error, and several packaging paths — building on Windows, or using a zip library that does not carry POSIX permissions — drop them silently. That also explains the version of this that appears after a CI migration which changed nothing about the code.
Container images reach the same error by a different route. The image declares an ENTRYPOINT, and an ImageConfig block in a CloudFormation or SAM template overrides it. Setting that block to an empty value replaces a correct entrypoint with nothing, and Lambda reports the same Runtime.InvalidEntrypoint despite the image being entirely fine on its own.
CloudWatch’s Errors metric: The error escaped your handler, so Lambda reports the invocation as failed and CloudWatch’s Errors metric counts it. LogStitch classified the invocation above as uncaught.
What it looks like in CloudWatch
This is the shape the failure arrives in: the lines of one invocation scattered among everything else the log group received at the same moment.
CloudWatch Logs Before
6 raw lines, in the order CloudWatch delivered them.
LogStitch After
The same lines, grouped into the invocation they belong to.
ErrorCold start · 188ms init6c1b8e40-3f27-4a95-b012-7d4e9a2c5b81
- 09:00:00.100PLAT
INIT_START Runtime Version: provided:al2023.v22 Runtime Version ARN: arn:aws:lambda:us-east-1::runtime:7f2a1c9b
- 09:00:00.284
Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]
- 09:00:00.290
{"errorType":"Runtime.InvalidEntrypoint","errorMessage":"RequestId: 6c1b8e40-3f27-4a95-b012-7d4e9a2c5b81 Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]"} - 09:00:00.402PLAT
START RequestId: 6c1b8e40-3f27-4a95-b012-7d4e9a2c5b81 Version: $LATEST
- 09:00:00.404PLAT
END RequestId: 6c1b8e40-3f27-4a95-b012-7d4e9a2c5b81
- 09:00:00.404PLAT
REPORT RequestId: 6c1b8e40-3f27-4a95-b012-7d4e9a2c5b81 Duration: 2.11 ms Billed Duration: 3 ms Memory Size: 512 MB Max Memory Used: 62 MB Init Duration: 188.44 ms Status: error Error Type: Runtime.InvalidEntrypoint
The panel on the right is generated by running the excerpt on the left through the same parser that powers the free web stitcher — it is what the tool actually produces for this input, not an illustration of it.
How to confirm it from the logs
Read the paths in the brackets — those are the only two places Lambda looks, in that order. The error appears immediately after INIT_START, before any output of your own, because the runtime process never started. On newer runtimes the REPORT line carries Error Type: Runtime.InvalidEntrypoint.
The word "valid" is doing real work here and is the part most often missed. A bootstrap file that exists but is not executable, or is built for the wrong architecture, fails this check exactly as a missing one does — the message is identical either way.
Causes, most likely first
The bootstrap file is not marked executable
Extract the deployment package and check the permission bits. Zips built on Windows, or built by a tool that does not preserve the executable bit, produce a file that is present and unrunnable. This is the single most common cause and the easiest to miss, because the file is visibly there.
It is named something other than bootstrap
List the package contents and look for the exact name. The provided runtimes require a file called bootstrap — not the name of your binary, not your handler string. A Go binary named after the service is the usual version of this.
The binary was built for the wrong architecture
Run file on the binary and compare it against the function's architecture. An arm64 build deployed to an x86_64 function cannot be executed, so it is present, executable, and not a valid bootstrap.
A container image's ENTRYPOINT was overridden with an empty value
For image-packaged functions, check whether the deployment sets ImageConfig. AWS documents a case where a CloudFormation template overrides the image's ENTRYPOINT with a null or empty value, which leaves nothing to execute even though the image itself is correct.
The file is at the wrong depth in the archive
Check whether bootstrap is at the root of the zip. A package built by zipping a directory rather than its contents puts the file at build/bootstrap, which is neither of the two paths Lambda searches.
Fixes
Set the executable bit, and keep it through packaging
The permission has to survive the zip. Building the archive on Linux or macOS with zip preserves it; some cross-platform tooling does not, which is why this reappears after a CI change that touched nothing else.
bashGOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bootstrap ./cmd/handler
chmod +x bootstrap
zip -q function.zip bootstrap
# Confirm the bit survived: the mode column should show -rwxr-xr-x
unzip -l function.zip
unzip -Z function.zip | head -3
Name it bootstrap, whatever your binary is called
The provided runtimes execute a file with this exact name. The handler string is not consulted for it, so renaming at build time is the fix rather than changing configuration.
bashgo build -o bootstrap ./cmd/orders
# not: go build -o orders-service ./cmd/orders
Build for the architecture the function is configured with
Cross-compiling to the wrong architecture produces a binary Lambda cannot execute. Check the function's Architectures and target it explicitly rather than relying on the build machine.
bashaws lambda get-function-configuration --function-name orders-fn \
--query 'Architectures'
# For arm64 functions:
GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o bootstrap ./cmd/handler
file bootstrap
Leave the image's ENTRYPOINT alone unless you mean to change it
For container images, an ImageConfig block that sets an empty entrypoint overrides what the Dockerfile declared. Omit the block entirely when the image already has the right entrypoint.
yamlResources:
OrdersFunction:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
ImageUri: !Ref ImageUri
# Do NOT set an empty ImageConfig — it overrides the Dockerfile's
# ENTRYPOINT with nothing, and Lambda then has nothing to run.
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 — Troubleshoot invocation issues
- AWS Lambda Developer Guide — Building a custom runtime
LogStitch finds this automatically, across every invocation in your account.
Paste a log excerpt into the free web stitcher and see it grouped, classified, and measured in your browser — nothing is uploaded. Or run the Mac app against your own AWS profiles and get the same view over every function you own.