What it means
Every Lambda runtime reports this failure in its own language's idiom, and the six phrasings look unrelated enough that they are usually searched separately. They are one problem: the handler configuration names a file, and Lambda could not load it.
| Runtime | What it says | |---|---| | Node.js | Cannot find module 'function' | | Python | Unable to import module 'function' | | Ruby | cannot load such file -- function | | Java | Class not found: function.Handler | | .NET | Unable to load type 'Function.Handler' from assembly 'Function' | | Go | fork/exec /var/task/function: no such file or directory |
The critical distinction — and the reason this is a separate problem from a missing dependency — is whose name is in the message. On Node, Cannot find module 'lodash' means a package is missing from node_modules. Cannot find module 'function', where function is the first half of your handler string, means Lambda went looking for your entry point and did not find it. Identical wording, completely different fix, and the only thing separating them is whether you recognise the name as your own.
The handler string is a path plus a name, and the path part is relative to the root of the archive with no searching. index.handler requires index.js at the top level — not in src/, not in dist/, not one directory down because the zip was built by compressing a folder rather than its contents. That last case is the single most common cause, and it is invisible until you list the archive, because everything about the build looks correct.
Case sensitivity produces the most frustrating variant. macOS and Windows filesystems are case-insensitive; the Lambda execution environment is Linux and is not. A handler of Index.handler against a file named index.js works on every developer machine and fails on deployment, with a message that gives no hint that capitalisation is the issue.
Go's phrasing deserves its own note because it covers more ground than it appears to. no such file or directory from fork/exec is what you get when the file is missing — and also when it exists but is not marked executable, or was compiled for a different architecture than the function is configured for. The message is the same in all three cases, so checking that the file is present is only the first of three things to verify.
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 · 186ms init71e0c4a3-8b26-4d59-9012-3f7a5c8e0b64
- 11:14:02.118PLAT
INIT_START Runtime Version: python:3.12.v41 Runtime Version ARN: arn:aws:lambda:us-east-1::runtime:9b1f5a2c
- 11:14:02.302ERROR
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': No module named 'lambda_function'
- 11:14:02.302
Traceback (most recent call last):
- 11:14:02.411PLAT
START RequestId: 71e0c4a3-8b26-4d59-9012-3f7a5c8e0b64 Version: $LATEST
- 11:14:02.413PLAT
END RequestId: 71e0c4a3-8b26-4d59-9012-3f7a5c8e0b64
- 11:14:02.413PLAT
REPORT RequestId: 71e0c4a3-8b26-4d59-9012-3f7a5c8e0b64 Duration: 2.09 ms Billed Duration: 3 ms Memory Size: 256 MB Max Memory Used: 61 MB Init Duration: 186.11 ms Status: error Error Type: Runtime.ImportModuleError
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
The distinguishing question is whether the name in the message is yours or a third party's. Cannot find module 'lodash' is a missing dependency. Cannot find module 'function', where function is the first half of your handler string, is this — Lambda looking for your entry point.
Read the handler configuration alongside it. The handler is file.export on Node and Python, package.Class::method on Java, and the name before the first dot is the file Lambda tried to load. If that name does not exactly match a file at the root of the archive, this is what happens.
It appears immediately after INIT_START with none of your own output, because the module never finished loading, and it fails identically on every invocation rather than intermittently.
Causes, most likely first
The handler string does not match the file in the package
Compare the configured handler against the archive's contents. index.handler requires a file called index.js (or .mjs/.cjs) at the root; lambda_function.lambda_handler requires lambda_function.py. A file renamed without updating the configuration produces this exactly.
The file is nested inside a directory in the archive
List the archive and check the paths. Zipping a directory rather than its contents puts the entry point at dist/index.js, and the handler must then be dist/index.handler — Lambda does not search subdirectories for it.
The case does not match
Compare the spelling character by character. The execution environment is Linux and case-sensitive; macOS and Windows filesystems are not. Index.js satisfies a local test and fails in production, and this is the version that passes every check before deployment.
The package contains source rather than build output
Look for .ts files where .js was expected, or a missing dist/. If the build step output to a directory the packaging step did not collect, the archive is full of files Lambda cannot use and missing the one it needs.
For Go and custom runtimes, the file is not executable
Check the permission bits. fork/exec …: no such file or directory is the Go phrasing, and it appears both when the file is genuinely absent and when it cannot be executed — a binary without the executable bit, or built for the wrong architecture.
Fixes
Match the handler string to the archive, whatever the runtime
The pattern differs per language but the rule is the same: the part before the last dot names the file, relative to the archive root.
yaml# index.js exporting `handler`
Handler: index.handler
# src/handlers/orders.js exporting `handler`
Handler: src/handlers/orders.handler
# lambda_function.py defining `lambda_handler`
Handler: lambda_function.lambda_handler
# com.example.OrderHandler implementing handleRequest
Handler: com.example.OrderHandler::handleRequest
Look inside the artifact rather than trusting the build
One command settles whether this is a packaging problem or a configuration one, and it is the step most often skipped.
bashunzip -l function.zip | head -20
# Zip the CONTENTS of the build directory, not the directory itself.
cd dist && zip -qr ../function.zip . && cd ..
Make the executable bit and architecture explicit for Go
The Go phrasing covers both "absent" and "cannot be executed", so check all three properties rather than only whether the file is there.
bashGOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bootstrap ./cmd/handler
chmod +x bootstrap
file bootstrap
Assert the entry point exists in CI
A one-line check in the pipeline turns a deployment failure into a build failure, where it is far cheaper to diagnose.
bashHANDLER_FILE=index.js
unzip -l function.zip | grep -q " ${HANDLER_FILE}$" \
|| { echo "${HANDLER_FILE} is not at the archive root" >&2; exit 1; }
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 deployment issues
- AWS Lambda Developer Guide — Lambda function handler
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.