[Lambda/NodeJS] Lambda Stop Working After Updating to Node.js 20

Table of Contents

1. Problem

If you are using AWS Lambda and update your Runtime to Node.js 20.x, you may see the error as follows:

Response
{
  "errorType": "ReferenceError",
  "errorMessage": "require is not defined in ES module scope, you can use import instead",
  "trace": [
    "ReferenceError: require is not defined in ES module scope, you can use import instead",
    "    at file:///var/task/index.mjs:2:68",
    "    at ModuleJob.run (node:internal/modules/esm/module_job:234:25)",
    "    at async ModuleLoader.import (node:internal/modules/esm/loader:473:24)",
    "    at async _tryAwaitImport (file:///var/runtime/index.mjs:1008:16)",
    "    at async _tryRequire (file:///var/runtime/index.mjs:1057:86)",
    "    at async _loadUserApp (file:///var/runtime/index.mjs:1081:16)",
    "    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"
  ]
}

This is because Node.js 20.x uses ECMAScript modules (ESM) by default. You need to update your code to use import instead of require.

The below code snippet is an example of reading message from SQS queue.

 1// Import the required SQS client from AWS SDK v3
 2const { SQSClient, ReceiveMessageCommand, DeleteMessageCommand } = require('@aws-sdk/client-sqs');
 3
 4// Create the SQS client
 5const sqsClient = new SQSClient({ region: 'ap-southeast-2' }); // Specify your AWS region
 6
 7// SQS queue URL
 8const queueUrl = 'https://xxx.us-east-1.amazonaws.com/xxx/testq';
 9
10// Lambda handler function
11exports.handler = async (event) => {
12  const params = {
13    QueueUrl: queueUrl,
14    MaxNumberOfMessages: 1, // Fetch one message
15    VisibilityTimeout: 20,
16    WaitTimeSeconds: 0,
17  };
18
19  try {
20    // Receive a message from SQS
21    const data = await sqsClient.send(new ReceiveMessageCommand(params));
22
23    if (data.Messages && data.Messages.length > 0) {
24      const message = data.Messages[0];
25      console.log('Message received:', message.Body);
26
27      // After processing the message, delete it from the queue
28      const deleteParams = {
29        QueueUrl: queueUrl,
30        ReceiptHandle: message.ReceiptHandle,
31      };
32      await sqsClient.send(new DeleteMessageCommand(deleteParams));
33
34      return {
35        statusCode: 200,
36        body: JSON.stringify({ message: 'Message processed and deleted successfully' }),
37      };
38    } else {
39      return {
40        statusCode: 200,
41        body: JSON.stringify({ message: 'No messages to process' }),
42      };
43    }
44  } catch (error) {
45    console.error('Error receiving or processing SQS message:', error);
46    return {
47      statusCode: 500,
48      body: JSON.stringify({ error: 'Failed to process the message' }),
49    };
50  }
51};

2. Solution

To completely fix the issue, you need to change two things:

  1. Replace require with import to comply with ES module syntax.
  2. Export the handler using export const handler instead of module.exports.

The updated code:

 1// Import the required SQS client from AWS SDK v3
 2import { SQSClient, ReceiveMessageCommand, DeleteMessageCommand } from '@aws-sdk/client-sqs';   <--- fixed
 3
 4// Create the SQS client
 5const sqsClient = new SQSClient({ region: 'ap-southeast-2' }); // Specify your AWS region
 6
 7// SQS queue URL
 8const queueUrl = 'https://xxx.us-east-1.amazonaws.com/xxx/testq';
 9
10// Lambda handler function
11export const handler = async (event) => {    <----fixed
12  const params = {
13    QueueUrl: queueUrl,
14    MaxNumberOfMessages: 1, // Fetch one message
15    VisibilityTimeout: 20,
16    WaitTimeSeconds: 0,
17  };
18
19  try {
20    // Receive a message from SQS
21    const data = await sqsClient.send(new ReceiveMessageCommand(params));
22
23    if (data.Messages && data.Messages.length > 0) {
24      const message = data.Messages[0];
25      console.log('Message received:', message.Body);
26
27      // After processing the message, delete it from the queue
28      const deleteParams = {
29        QueueUrl: queueUrl,
30        ReceiptHandle: message.ReceiptHandle,
31      };
32      await sqsClient.send(new DeleteMessageCommand(deleteParams));
33
34      return {
35        statusCode: 200,
36        body: JSON.stringify({ message: 'Message processed and deleted successfully' }),
37      };
38    } else {
39      return {
40        statusCode: 200,
41        body: JSON.stringify({ message: 'No messages to process' }),
42      };
43    }
44  } catch (error) {
45    console.error('Error receiving or processing SQS message:', error);
46    return {
47      statusCode: 500,
48      body: JSON.stringify({ error: 'Failed to process the message' }),
49    };
50  }
51};

If this post helped you to solve a problem or provided you with new insights, please upvote it and share your experience in the comments below. Your comments can help others who may be facing similar challenges. Thank you!
Buy Me A Coffee
DigitalOcean Referral Badge
Sign up to get $200, 60-day account credit !