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 Speaker

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!


Share This Article

Related Articles


Lazy loading background images to improve load time performance

Lazy loading of images helps to radically speed up initial page load. Rich site designs often call for background images, which can't be lazily loaded in the same way. How can we keep our designs, while optimising for a fast initial load?

Using Google Sheets as a RESTful JSON API

Save time by not building backends for simple CRUD apps. Use Google Sheets as both a free backend and JSON API endpoint!

Serverless caching and proxying with Cloudflare Workers

Using Cloudflare Workers we can quickly build an effective API proxy, without spinning up any additional hardware. Whether its needing a CORS proxy, speeding up slow APIs via caching, or rate limit management on stingy APIs, this serverless tech is as easy to set up as it is powerful.

Idempotency - what is it, and how can it help our Laravel APIs?

Idempotency is a critical concept to be aware of when building robust APIs, and is baked into the SDKs of companies like Stripe, Paypal, Shopify, and Amazon. But what exactly is idempotency? And how can we easily add support for it to our Laravel APIs?

Calculating rolling averages with Laravel Collections

Rolling averages are perfect for smoothing out time-series data, helping you to gain insight from noisy graphs and tables. This new package adds first-class support to Laravel Collections for rolling average calculation.

More