Solving AWS Lambda's "Cannot find module 'index'" Problem
Recently I returned to an old Node app that runs on AWS Lambdas. When they work well, Lambdas are a wonderful piece of serverless technology, allowing applications to scale up and down as required. I finished my changes, prepped the app for deployment, uploaded it, then stumbled into a small AWS Lambda pitfall entirely of my own making, but one surprisingly tough to debug, given the cryptic error message when I tried to access the Lambda in the browser:
undefined ERROR Uncaught Exception {
"errorType": "Runtime.ImportModuleError",
"errorMessage": "Error: Cannot find module 'index'\nRequire stack:\n- /var/runtime/index.mjs",
"stack": [
"Runtime.ImportModuleError: Error: Cannot find module 'index'",
"Require stack:",
"- /var/runtime/index.mjs",
" at _loadUserApp (file:///var/runtime/index.mjs:1087:17)",
" at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1119:21)",
" at async start (file:///var/runtime/index.mjs:1282:23)",
" at async file:///var/runtime/index.mjs:1288:1"
]
}
At first glance, this was baffling. Why was it looking for index.mjs as an entry point to the lambda? My app had always had an index.js, or a handler.js. Had AWS silently updated Lambda to mandate ES modules? Was my trusty old Node.js app suddenly outdated overnight? Possible, but as I chased cryptic and misleading error messages deeper and deeper down a google/stack overflow rabbit hole, I was getting dangerously close to "is there a bug in the compiler?" territory. As usual, the real problem sat not in the code, but firmly between the chair and the keyboard.
What's Actually Happening?
When a Lambda is invoked, it's effectively loading a zipped folder of code into its container, then executing it. This can be handled automatically when granting the right IAM access to frameworks like Serverless, or you can manually upload a zip to S3 and link that to your Lambda. The latter approach is much more manual and time-consuming, but on this project I was working within a pair of particularly-restrictive IAM handcuffs, so was stuck with the manual approach. In either case, an archive of your project is ultimately linked to your Lambda.
The runtime then expects your application's entry file (index.js, handler.js, etc) to be located at the root of your zip archive. If, like me, you accidentally zip the entire folder containing your app (instead of just its contents), Lambda won't find your entry point. It panics and gives you the confusing message about a missing index module, defaulting to the assumption index.mjs should be in use.
The error is a red herring, as Lambda doesn't need an index.mjs. It's just AWS's way of saying, "I can't find your entry file at the root of the zip."
The Fix
Make sure you zip your project's contents, not the folder itself:
What I had done:
zip -r function.zip myLambdaFunctionFolder
What I should have done:
cd myLambdaFunctionFolder
zip -r ../function.zip .
I uploaded the correct zip, linked it to my Lambda, and normal service was resumed. Hopefully, this saves someone else the 30 minutes of head-desking it cost me!
CyberWiseCon 2025
In May 2025, I'll be presenting Digital Cat-and-Mouse: Strategies to Outsmart Scrapers, Phishers, and Thieves at CyberWiseCon in Vilnius, Lithuania. From selling 10 Downing St, to moving the Eiffel Tower to Dublin, this talk covers real-world examples of unconventional ways to stop scrapers, phishers, and content thieves. You'll gain practical insights to protect assets, outsmart bad actors, and avoid the mistakes we made along the way!
Get your ticket now and I'll see you there!