53

I am trying to create a simple lambda function, and I'm running into an error.

My code is basically

console.log('Loading function');

exports.handler = function(event, context) {
    console.log('value1 =', event.key1);
    console.log('value2 =', event.key2);
    console.log('value3 =', event.key3);
    context.succeed(event.key1);  // Echo back the first key value
    // context.fail('Something went wrong');
}

in a helloworld.js file. I zip that up and upload it as a zip file in the creating a lambda function section, and I keep getting this error:

{
  "errorMessage": "Cannot find module 'index'",
  "errorType": "Error",
  "stackTrace": [
    "Function.Module._resolveFilename (module.js:338:15)",
    "Function.Module._load (module.js:280:25)",
    "Module.require (module.js:364:17)",
    "require (module.js:380:17)"
  ]
}

Does anyone have any ideas?

BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
jstnchng
  • 2,161
  • 4
  • 18
  • 31

7 Answers7

68

The name of your file needs to match the module name in the Handler configuration. In this case, your Handler should be set to helloworld.handler, where helloworld is the file that would be require()'d and handler is the exported function. Then it should work with the same zip file.

AWS Lambda configuration screenshot

James
  • 11,721
  • 2
  • 35
  • 41
  • 2
    I copied your function test, uploaded and ran it, and successfully got the output `value1`. Have you changed it? – James Jun 05 '15 at 17:23
  • 1
    Yes, just played around a little and got it working. On an unrelated note, I want to run java executables in a js file- is it a good idea to wrap all of that inside of my exports.handler block? – jstnchng Jun 05 '15 at 17:26
  • 2
    I'm afraid that's beyond me, but I'm glad the zip file is working. – James Jun 05 '15 at 17:42
  • 3
    You'll also see this error if you try to upload a zipped folder containing your lambda files You must zip and upload the contents of the directory, not the directory itself. – Bill Apr 25 '16 at 19:19
  • Does this still work? I don't see a handler window anymore in lambda configuration in the new interface – loknar Aug 20 '20 at 00:59
63

Make sure your index.js is in the root of the zipfile and not in a subdirectory.

In my case I had the name of the module matching the name of the file and the exported handler, the real problem was macOS and the zip program which basically creates a folder inside the zip file so when uncompressed in AWS Lambda engine the index.js ends in a subdirectory.

Using Finder

Don't right click and compress the directory, instead select the files individual files like index.js, package.json and the node_modules directory and right-click to compress, you may end up with a file Archive.zip in the same directory. The name of the zip file is not going to be fancy but at least it will work when you submit it to AWS Lambda.

Using the command line

You could make the same mistake using the command line with zip -r function.zip function which basically creates a zip file with a directory called function in it, instead do:

$ zip function.zip index.js package.json node_modules

adding: index.js (deflated 47%)
adding: package.json (deflated 36%)
adding: node_modules/ (stored 0%)

How to know verify your zip file

Using finder, if you double click the zip file and it uncompresses in a subdirectory then Lambda won't be able to see the file as index.js lives in that subdirectory.

Using the command line and zipinfo:

$ zipinfo function.zip | grep index.js | more
-rw-r--rw-  2.1 unx     1428 bX defN 27-Jul-16 12:21 function/index.js

Notice how index.js ended up inside the subdirectory function, you screwed up.

$ zipinfo function.zip | grep index.js | more
-rw-r--rw-  3.0 unx     1428 tx defN 27-Jul-16 12:21 index.js

Notice that index.js is not inside a subfolder, this zip file will work in AWS Lambda.

Leveraging npm commands to zip the function

So I added a script to my package to zip the project files for me just by running npm run zip

{
  "name": "function",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "zip": "zip function.zip package.json *.js node_modules"
  },
  "dependencies": {
    "aws-sdk": "^2.4.10"
  }
}

$ npm run zip

> function@1.0.0 zip 
> zip function.zip package.json *.js node_modules

  adding: package.json (deflated 41%)
  adding: index.js (deflated 47%)
  adding: local.js (deflated 42%)
  adding: node_modules/ (stored 0%)
bithavoc
  • 1,539
  • 15
  • 20
  • 5
    "Don't right click and compress the directory" - what I needed. thanks! – mauris Nov 02 '16 at 04:54
  • Awesome!! Have been searching this for a couple of days!! I was repeatedly getting this **cannot find the module error**. BTW what is the exact difference between right-click and compress to using the zip cli as mentioned above. – Lakshman Diwaakar Apr 13 '17 at 02:09
  • 7
    In your example: "$ zip function.zip index.js package.json node_modules" is missing -r meaning the node_modules folder will be empty - which you can see in the output from your sample (adding: node_modules/ (stored 0%)) -- I don't think that's what you want right? – Quad64Bit Jul 18 '17 at 17:11
9

Here is an advance way with AWS CLI. It will save your time in long term use.

First of all you should install and configure AWS CLI:

http://docs.aws.amazon.com/cli/latest/userguide/installing.html

1) Create an archive

$ zip -r lambda *

It will create for us lambda.zip file with all folders and files in the our current location.

2) Get role ARN

$ aws iam list-roles | grep "your_role"

It will return to us ARN that we will use with our lambda. You should create it by your hands

Example for list-roles

3) Create our lambda

$ aws lambda create-function --function-name "your_lambda_name" --zip-file fileb://lambda.zip --handler index.handler --runtime nodejs6.10 --timeout 15 --role COPY_HERE_YOUR_ARN_FROM_THE_STEP_2

We are done!

Jingo Bingo
  • 93
  • 1
  • 5
  • Remarkable! Instructions that actually work. It seems Amazon has no intention of people actually using Lambda. Thanks for the info! – Sam Jan 17 '18 at 18:17
  • This works like a champ! Be careful while creating the zip file. Get into the directory where your project files are residing and then do this: zip -r ../my_project.zip * – Mahan Feb 24 '20 at 05:34
0

Automation - using Grunt

Complete AWS Lambda Seed project is available on Git.

Step 1: Init npm module

npm init

Step 2: Install Grunt

npm install --save-dev grunt grunt-cli

Step 3: Install grunt-aws-lambda

npm install --save-dev grunt-aws-lambda

Step 4: Create Folder for Lambda service

# Create directory
mkdir lambdaTest

# Jump into folder
cd lambdaTest

# Create service file
touch lambdaTest.js

# Initialize npm
npm init

Keep your logic/code into lambdaTest.js

'use strict'

exports.handler = (event, context, callback) => {
    console.log("Hello it's looks like working");
};

Step 5: Create Gruntfile.js

Navigate back to root folder touch Gruntfile.js

'use strict'
module.exports = function (grunt) {
    grunt.initConfig({
        lambda_invoke: {
            lambdaTest: {
                options: {
                    file_name: "lambdaTest/lambdaTest.js",
                    event: "lambdaTest/test.json",
                }
            }
        },
        lambda_package: {
            lambdaTest: {
                options: {
                    package_folder: 'lambdaTest/'
                }
            }
        },
        lambda_deploy: {
            lambdaTest: {
                arn: 'arn:aws:lambda:eu-central-1:XXXXXXXX:function:lambdaTest',
                options: {
                    credentialsJSON: 'awsCredentials.json',
                    region: "eu-central-1"
                },
            }
        },
    });

    grunt.loadNpmTasks('grunt-aws-lambda');


    grunt.registerTask('ls-deploy', ['lambda_package:lambdaTest', 'lambda_deploy:lambdaTest']);
};

Step 6: Create awsCredentials.js

Create AWS IAM User with custom policy, Custom policy should have access to lambda:GetFunction, lambda:UploadFunction, lambda:UpdateFunctionCode, lambda:UpdateFunctionConfiguration and iam:PassRole

{
    "accessKeyId": "XXXXXXXXXXXXXXXXXXXX",
    "secretAccessKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

Step 7: Create a zip and deploy to AWS Lambda.

ls-deploy is custom task created by in Gruntfile above, which creates a zip of source code and deploy to Lambda.

grunt ls-deploy

Complete AWS Lambda Seed project is available on Git.

jaym
  • 1,253
  • 13
  • 18
0

Let's take a folder named 'sample' as an example which we want to zip. Let's assume there are some subfolders or files within the sample folder.

Q. What you have to do?
A: Following are the steps:

  1. Go inside the folder 'sample'.
  2. select all required files or subfolders.
  3. Right click on any one and select send to.
  4. You will see Archive.zip, simply save it in your laptop anywhere you want.
  5. Upload this zip as Amazon lambda function.

Q. What not to do?
A: Do not zip 'sample' folder. It won't work.

halfer
  • 19,824
  • 17
  • 99
  • 186
Saket Suraj
  • 71
  • 1
  • 1
  • 8
0

The same error occurs when you use the wrong runtime language

Dmitry Grinko
  • 13,806
  • 14
  • 62
  • 86
-3

Its because in exports.handler, you are not referencing the index function. This can be solved in a more simpler way

Try this,

console.log('Loading function');

    exports.handler = function index (event, context) {
        console.log('value1 =', event.key1);
        console.log('value2 =', event.key2);
        console.log('value3 =', event.key3);
        context.succeed(event.key1);  // Echo back the first key value
        // context.fail('Something went wrong');
    }
Kishor Unnikrishnan
  • 1,928
  • 4
  • 21
  • 33