aws/aws-sdk-js-v3

make AWS SDK JS v2 and v3 available with ESM in AWS Lambda

shishkin opened this issue ยท 71 comments

Describe the bug

Nodejs lambda is not able to find AWS SDK.

Your environment

SDK version number

Tried latest v2 and latest v3 with same effect:
@aws-sdk/client-s3@npm:3.48.0
aws-sdk@npm:2.1062.0

Is the issue in the browser/Node.js/ReactNative?

Node.js

Details of the browser/Node.js/ReactNative version

Node.js 14 AWS Lambda runtime

Steps to reproduce

Here is the code of the lambda:

// src/lambda.ts
import { S3 } from "aws-sdk";
import { URLSearchParams } from "node:url";
var { REGION, BUCKET_NAME } = process.env;
var s3 = new S3({ region: REGION });
var handler = async (e) => {
  console.debug("Event:", e);
  const { message } = e;
  const greeting = hello(message);
  const s3result = await s3.putObject({
    Bucket: BUCKET_NAME,
    Key: `greetings/hello.txt`,
    Tagging: new URLSearchParams({
      type: "greeting"
    }).toString(),
    ContentType: "text/plain; charset=UTF-8",
    Body: greeting
  }).promise();
  console.debug("S3 result:", s3result);
};
var hello = (message) => `Hello, ${message}!`;
export {
  handler,
  hello
};

Observed behavior

Lambda fails with error:

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'aws-sdk' imported from /var/task/index.mjs

Expected behavior

Reading the guide, I understand that aws-sdk should be already available on Nodejs runtimes.

Additional context

I'm trying to make use of newly announced ESM support in the Nodejs14 AWS Lambda runtime and make the smallest possible lambda bundle, hence the reason for not bundling AWS SDK.

vudh1 commented

Hi @shishkin thanks for reaching out. Make sure that you install the package aws-sdk in the right directory. Can we know how do you install?

TimNN commented

FYI: I ran into a similar problem and was able to make this work by creating and using a require function as documented here: https://nodejs.org/api/module.html#modulecreaterequirefilename

@TimNN to better understand your solution, do you then const S3 = require("aws-sdk/S3") instead of importing it?

TimNN commented

Almost. Importing specific clients did not work for me, but const { EC2 } = require('aws-sdk'); does.

Thanks @TimNN! I've built up on your suggestion to support TypeScript transpiling using CDK Node.js bundling:

    new NodejsFunction(this, "Lambda", {
      entry: fileURLToPath(new URL("handler.ts", import.meta.url)),
      bundling: {
        format: OutputFormat.ESM,
        target: "esnext",
        banner: `const AWS=await (async ()=>{const { createRequire }=(await import("node:module")).default;const require=createRequire(import.meta.url);return require("aws-sdk");})();`,
      },
    });

@vudh1 could you please provide an update on the triage of this bug? While the workaround has been identified, lambda runtime should support ESM imports of aws-sdk natively.

simlu commented

Just ran into this as well. Weird bug and hard to understand why it's happening.

Looks like importing absolute path(/var/runtime(...)) is a workaround... but an ugly one.

Also having this issue. I think this is a bug with the lambda runtime's es module support and not a bug with the sdk itself. It's at least the fifth one I've run into at this point. I cannot recommend enough sticking with CommonJS or a transpiiler for the time being.

Is there somewhere more generic we can submit this bug for triage?

@FrancoCorleone what would be the absolute path for aws-sdk package?

import AWS from '/var/runtime/node_modules/aws-sdk/lib/aws.js'
this works for me

Same issue here. Trying to import aws-sdk v2 within a TypeScript module compiled in ES2022, using ESM imports:

import AWS from 'aws-sdk';

The lambda fails with the error: Cannot find package 'aws-sdk' imported from /var/task/index.js\nDid you mean to import aws-sdk/lib/aws.js?

A valid workaround is to add aws-sdk as a dependency in the TypeScript module's package.json (npm i aws-sdk). This allows the module's code to use the locally installed copy of aws-sdk, not the one available in the lambda runtime.

I can attest that I have seen the same issue but as it relates to deploying a layer for the AWS Lambda on a Node.js 14.x ARM env. No matter what I do in IAM I can't get the Lambda to discover the client-specific library:

const { S3Client } = require("@aws-sdk/client-s3");

const S3 = new S3Client({ region: process.env.AWS_REGION ?? "us-east-1" });

My IAM policy document (assinged via a role to the Lambda) is([xxxxx] below represents a real account no.):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:GetLayerVersion",
                "lambda:PublishVersion"
            ],
            "Resource": [
                "arn:aws:lambda:*:[xxxxx]:function:*",
                "arn:aws:lambda:us-east-1:[xxxxx]:layer:document-uploading-layer:2"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "lambda:PublishLayerVersion",
            "Resource": "arn:aws:lambda:us-east-1:[xxxxx]:layer:document-uploading-layer:2"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:ListLayerVersions",
                "lambda:ListLayers"
            ],
            "Resource": "*"
        }
    ]
}

The only work around I have is to create a deployment package that includes the node_modules directory as a sibling of the index.js export.handler = file.

I can attest that I have seen the same issue but as it relates to deploying a layer for the AWS Lambda on a Node.js 14.x ARM env. No matter what I do in IAM I can't get the Lambda to discover the client-specific library:

const { S3Client } = require("@aws-sdk/client-s3");

const S3 = new S3Client({ region: process.env.AWS_REGION ?? "us-east-1" });

My IAM policy document (assinged via a role to the Lambda) is([xxxxx] below represents a real account no.):

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:GetLayerVersion",
                "lambda:PublishVersion"
            ],
            "Resource": [
                "arn:aws:lambda:*:[xxxxx]:function:*",
                "arn:aws:lambda:us-east-1:[xxxxx]:layer:document-uploading-layer:2"
            ]
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "lambda:PublishLayerVersion",
            "Resource": "arn:aws:lambda:us-east-1:[xxxxx]:layer:document-uploading-layer:2"
        },
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": [
                "lambda:ListLayerVersions",
                "lambda:ListLayers"
            ],
            "Resource": "*"
        }
    ]
}

The only work around I have is to create a deployment package that includes the node_modules directory as a sibling of the index.js export.handler = file.

This actually isn't true. I found this doc. for v. 14+ buried: https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html#configuration-layers-path

The path has to match.

Is it really that difficult to solve? I'm struggling with local development because of that...

This is preventing people from using es6 features on Lambda which is not good

as @EPMatt said, a simple workaround is just to move aws-sdk from your devDependencies into dependencies so it gets bundled with your package. Creates 70MB of extra bloat (per function obvs) but I'm sure that's a drop in the ocean to lambda/npm aficionados.

This is by far the worst idea actually. That increases costs, makes longer to deploy etc.
What I did to "solve" it for now was to install aws-sdk globally for my node version (handled by nvm) and then created a symlink from /var/runtime/*/aws-sdk to my globally installed sdk. At least I can work locally now. But this is a part of a bigger problem with using ESM in lambdas, look here for more information

as @EPMatt said, a simple workaround is just to move aws-sdk from your devDependencies into dependencies so it gets bundled with your package. Creates 70MB of extra bloat (per function obvs) but I'm sure that's a drop in the ocean to lambda/npm aficionados.

I have this setup, not working neither. It's a problem of using the import keyword

This is by far the worst idea actually. That increases costs, makes longer to deploy etc. What I did to "solve" it for now was to install aws-sdk globally for my node version (handled by nvm) and then created a symlink from /var/runtime/*/aws-sdk to my globally installed sdk. At least I can work locally now. But this is a part of a bigger problem with using ESM in lambdas, look here for more information

I don't think it could be a problem. It's slow when you zip everything and upload, but if you only upload your changes after initial upload or use sam || serverless it may skip the node_modules folder because it is already included.

@vudh1 Any update on this? We are also running into this same problem. What is the official way to use the sdk that is built into the lambda runtime with es6?

Seriously guys. Use my solution, problem solved until they finally fix it

No offense, but your solution is a giant hack and as you stated in later post it makes local development difficult. I have read about symlinks being a possible solution to that, but it is one hack after another and fairly soon it gets so messy that maintaining our dev environment takes more work than programming our code.

For now it is easier to just go back to using CommonJs.

For now it's easier to specify the full path. But not ideal.
I noticed specifying full path is not necessary when using sam local invoke, but it is necessary when running up in aws.

@rmclaughlin-nelnet No offense but that's BS :D
But I get where maybe it gets confusing.So there are two issues:

  1. Using layers with ESM approach - doesn't work. What I recommend is to create layer structure and simply, in package.json put that module as local dependency. Then during npm install, symlink is implicitly created and then you can zip it with library embedded.
  2. Now, for the aws-sdk. Just install it "globally". For example in your root project in node_modules or in your nvm distribution. Whatever. And then create a symlink globally in your system that redirects from /var/runtime(...) to your local distribution. \

From that point on, you can simply work with it. Or you can stick with CommonJS, that works too

kuhe commented

The AWS SDK for JavaScript v2 is imported with the name aws-sdk (non-scoped). This is available in AWS Lambda, but only with require.

The AWS SDK JS v3, which is this repository, is not available in AWS Lambda currently, unless you upload it in your own application bundle. This one is imported with @aws-sdk/***-client and other packages under the @aws-sdk/ prefix. We are working with AWS Lambda to make the AWS SDK v3 available without needing to upload your own copy, but cannot provide a timeline.

Thanks @kuhe !

@kuhe but the truth is lambda is struggling with ES imports from layers altogether. So both have to be sorted for it to work.

mcqj commented

Thanks @kuhe
The very first line of the V3 README says

The [version 3.x](https://github.com/aws/aws-sdk-js-v3) of the AWS SDK for JavaScript is generally available. For more information see the [Developer Guide](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/) or [API Reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/index.html).

Nowhere in the README are there any caveats about using it with Lambda. Perhaps, a note at the top of that file would save other developers a lot of time.

if anyone wants the copy-pastable workaround code:

import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const aws = require('aws-sdk');

and in my deploy script:

npm i --omit=dev
## deploy lambda
.
.
.

## reinstall the dev dependencies locally
npm i

So now we have: local aws-sdk, lambda aws-sdk and no impact on zipped code size.

On lambda aws-sdk is installed in /var/runtime/node_modules/ which is added to the NODE_PATH so require('aws-sdk') can resolve it. However esm does not use NODE_PATH so it will error with Cannot find package 'aws-sdk' imported from /var/task/index.mjs\nDid you mean to import aws-sdk/lib/aws.js?.

This is an issue with lamda, not the v2 sdk (aws-sdk) or the v3 sdk (@aws-sdk/*-client)

This is an issue with lamda, not the v2 sdk (aws-sdk) or the v3 sdk (@aws-sdk/*-client)

@everett1992 isn't SDK part of AWS Lambda product offering? At some point customers don't care which team messed up when advertised product features don't work together.

Same error leaded me here, any update?

Same here.

Same issue...

x3

+1

+1 I would consider this a bug though, not a feature-request, I would agree that it's not a bug for aws-sdk-js-v3 team.
aws-sdk should be available in runtime.
using NODE_PATH is deprecated nodejs/modules#534

same here...

This is a bug. trying to separate Lambda vs Lambda with NodeJS build in vs the aws-sdk is not the point

looks like this is solved ๐ŸŽ‰, at least for the new nodejs18.x runtime!

Hi everyone, I am facing the same error.
I saw the new update but still don't understand how to fix my lambda function

here is the code

'use strict'

const AWS = require('aws-sdk')

const s3 = new AWS.S3()

// Change this value to adjust the signed URL's expiration
const URL_EXPIRATION_SECONDS = 30000000
const uploadBucket = "videosbefore-detection"

// Main Lambda entry point
exports.handler = async (event) => {
  return await getUploadURL(event)
}

const getUploadURL = async function(event) {
  const randomID = parseInt(Math.random() * 10000000)
  const Key = `${randomID}.mp4`

  // Get signed URL from S3
  const s3Params = {
    Bucket: uploadBucket,
    Key,
    Expires: URL_EXPIRATION_SECONDS,
    ContentType: 'video/mp4',

  }

  console.log('Params: ', s3Params)
  const uploadURL = await s3.getSignedUrlPromise('putObject', s3Params)

  return JSON.stringify({
    uploadURL: uploadURL,
    Key
  })
}

the error is ->
"require is not defined in ES module scope, you can use import instead"

https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-lambda/

If anyone still struggles with solution, this worked for me:

import * as AWS from "@aws-sdk/client-lambda"; const client = new AWS.Lambda({ region: "REGION" });

Then use as regular.

I had this same issue during the tutorial.

FYI: I ran into a similar problem and was able to make this work by creating and using a require function as documented here: https://nodejs.org/api/module.html#modulecreaterequirefilename

I am using the code suggested here to find require, but the sdk module is still missing. Here is my code. I am editing the lambda function with the AWS Lambda code editor online.

import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);

const AWS = require('aws-sdk');

The error msg:

{
  "errorType": "Runtime.ImportModuleError",
  "errorMessage": "Error: Cannot find module 'aws-sdk'\nRequire stack:\n- /var/task/index.mjs",
  "trace": [
    "Runtime.ImportModuleError: Error: Cannot find module 'aws-sdk'",
    "Require stack:",
    "- /var/task/index.mjs",
    "    at _loadUserApp (file:///var/runtime/index.mjs:1000:17)",
    "    at async UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:1035:21)",
    "    at async start (file:///var/runtime/index.mjs:1200:23)",
    "    at async file:///var/runtime/index.mjs:1206:1"
  ]
}

Why is this still a problem an entire year later? You can't use the aws-sdk with NodeJS ES6 as expected. What a pain. Please fix it. Forward it to the Lambda team, it's their problem afaict.

As @TonyIvanova mentioned, this worked for me as a workaround: (thanks!)

import * as AWS from "@aws-sdk/client-lambda"; const client = new AWS.Lambda({ region: "REGION" });

Why is this still a problem an entire year later? You can't use the aws-sdk with NodeJS ES6 as expected. What a pain. Please fix it. Forward it to the Lambda team, it's their problem afaict.

As @TonyIvanova mentioned, this worked for me as a workaround: (thanks!)

import * as AWS from "@aws-sdk/client-lambda"; const client = new AWS.Lambda({ region: "REGION" });

While I generally agree with you that the rollout is pretty sloppy, you can use v3 with esm in node18.x without any workarounds.

Yes, upgrading to Node 18 runtime works.

Yes, upgrading to Node 18 runtime works.

Using Node 18.x for a Lambda script, import AWS from "aws-sdk"; still produces this error for me. That is also what the documentation says to use.

Yes, upgrading to Node 18 runtime works.

Using Node 18.x for a Lambda script, import AWS from "aws-sdk"; still produces this error for me. That is also what the documentation says to use.

That's v2, it's not included by default on lambda 18.x, if you want to use it you'll need to install it in your own project.

For v3 you can familiarise yourself with https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/

@jredbeard please take a look at https://github.com/markusl/aws-cdk-nodejs18-lambda-aws-js-sdk-v3 about how you could use JS SDK v3 with Lambda to deploy successfully. Let me know if this is what you are trying to do!

import AWS from '/var/runtime/node_modules/aws-sdk/lib/aws.js' this works for me

it doesnt work for me
I uploaded this file to aws codesource:

index.mjs


import AWS from '/var/runtime/node_modules/aws-sdk/lib/aws.js';

AWS.config.update({
  region: "us-east-1",
});
const dynamodb = new AWS.DynamoDB.DocumentClient();
const dynamodbTableName = "product-inventory";
const healthPath = "/health";
const productPath = "/product";
const productsPath = "/products";

exports.handler = async function (event) {
  console.log("Request event: ", event);
  let response;
  switch (true) {
    case event.httpMethod === "GET" && event.path === healthPath:
      response = buildResponse(200);
      break;
    case event.httpMethod === "GET" && event.path === productPath:
      response = await getProduct(event.queryStringParameters.productId);
      break;
    case event.httpMethod === "GET" && event.path === productsPath:
      response = await getProducts();
      break;
    case event.httpMethod === "POST" && event.path === productPath:
      response = await saveProduct(JSON.parse(event.body));
      break;
    case event.httpMethod === "PATCH" && event.path === productPath:
      const requestBody = JSON.parse(event.body);
      response = await modifyProduct(
        requestBody.productId,
        requestBody.updateKey,
        requestBody.updateValue
      );
      break;
    case event.httpMethod === "DELETE" && event.path === productPath:
      response = await deleteProduct(JSON.parse(event.body).productId);
      break;
    default:
      response = buildResponse(404, "404 Not Found");
  }
  return response;
};

async function getProduct(productId) {
  const params = {
    TableName: dynamodbTableName,
    Key: {
      productId: productId,
    },
  };
  return await dynamodb
    .get(params)
    .promise()
    .then(
      (response) => {
        return buildResponse(200, response.Item);
      },
      (error) => {
        console.error(
          "Do your custom error handling here. I am just gonna log it: ",
          error
        );
      }
    );
}

async function getProducts() {
  const params = {
    TableName: dynamodbTableName,
  };
  const allProducts = await scanDynamoRecords(params, []);
  const body = {
    products: allProducts,
  };
  return buildResponse(200, body);
}

async function scanDynamoRecords(scanParams, itemArray) {
  try {
    const dynamoData = await dynamodb.scan(scanParams).promise();
    itemArray = itemArray.concat(dynamoData.Items);
    if (dynamoData.LastEvaluatedKey) {
      scanParams.ExclusiveStartkey = dynamoData.LastEvaluatedKey;
      return await scanDynamoRecords(scanParams, itemArray);
    }
    return itemArray;
  } catch (error) {
    console.error(
      "Do your custom error handling here. I am just gonna log it: ",
      error
    );
  }
}

async function saveProduct(requestBody) {
  const params = {
    TableName: dynamodbTableName,
    Item: requestBody,
  };
  return await dynamodb
    .put(params)
    .promise()
    .then(
      () => {
        const body = {
          Operation: "SAVE",
          Message: "SUCCESS",
          Item: requestBody,
        };
        return buildResponse(200, body);
      },
      (error) => {
        console.error(
          "Do your custom error handling here. I am just gonna log it: ",
          error
        );
      }
    );
}

async function modifyProduct(productId, updateKey, updateValue) {
  const params = {
    TableName: dynamodbTableName,
    Key: {
      productId: productId,
    },
    UpdateExpression: `set ${updateKey} = :value`,
    ExpressionAttributeValues: {
      ":value": updateValue,
    },
    ReturnValues: "UPDATED_NEW",
  };
  return await dynamodb
    .update(params)
    .promise()
    .then(
      (response) => {
        const body = {
          Operation: "UPDATE",
          Message: "SUCCESS",
          UpdatedAttributes: response,
        };
        return buildResponse(200, body);
      },
      (error) => {
        console.error(
          "Do your custom error handling here. I am just gonna log it: ",
          error
        );
      }
    );
}

async function deleteProduct(productId) {
  const params = {
    TableName: dynamodbTableName,
    Key: {
      productId: productId,
    },
    ReturnValues: "ALL_OLD",
  };
  return await dynamodb
    .delete(params)
    .promise()
    .then(
      (response) => {
        const body = {
          Operation: "DELETE",
          Message: "SUCCESS",
          Item: response,
        };
        return buildResponse(200, body);
      },
      (error) => {
        console.error(
          "Do your custom error handling here. I am just gonna log it: ",
          error
        );
      }
    );
}

function buildResponse(statusCode, body) {
  return {
    statusCode: statusCode,
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(body),
  };
}


in cloudwatch:



2023-02-06T06:03:18.362Z	undefined	ERROR	Uncaught Exception 	{
    "errorType": "Error",
    "errorMessage": "Cannot find module '/var/runtime/node_modules/aws-sdk/lib/aws.js' imported from /var/task/index.mjs",
    "code": "ERR_MODULE_NOT_FOUND",
    "stack": [
        "Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/var/runtime/node_modules/aws-sdk/lib/aws.js' imported from /var/task/index.mjs",
        "    at new NodeError (node:internal/errors:393:5)",
        "    at finalizeResolution (node:internal/modules/esm/resolve:328:11)",
        "    at moduleResolve (node:internal/modules/esm/resolve:965:10)",
        "    at moduleResolveWithNodePath (node:internal/modules/esm/resolve:909:12)",
        "    at defaultResolve (node:internal/modules/esm/resolve:1173:79)",
        "    at nextResolve (node:internal/modules/esm/loader:163:28)",
        "    at ESMLoader.resolve (node:internal/modules/esm/loader:841:30)",
        "    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)",
        "    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)",
        "    at link (node:internal/modules/esm/module_job:75:36)"
    ]
}

taos commented

To other people that found this tread from googling on the error message, and are still confused -- if you want "const AWS = require('aws-sdk');" to work, just pick "Node.js 14.x" as your Lambda Runtime.

Is this issue still not resolved?

I'm also facing face issue.

This still seems to be an issue, I've deployed a node18 function with ESM and when trying to do something with DynamoDB it tells me there is no ESM available:

SyntaxError: Named export 'ReturnValue' not found. The requested module '@aws-sdk/client-dynamodb' is a CommonJS module, which may not support all module.exports as named exports.\nCommonJS modules can always be imported via the default export, for example using:\n\nimport pkg from '@aws-sdk/client-dynamodb';\nconst { ReturnValue, UpdateItemCommand } = pkg;\n

When I bundle the respective modules myself, it works just fine. My conclusion is that the Lambda bundled SDK v3 doesn't support ESM still?

I also have this issue
Any ideas?

I could trace it back to "ReturnValue" being not available which is an enum. My guess is that the version bundled on Lambda doesn't export this.

Any update on this issue ?

Hi people, sorry for any delays answering to this issue. With lambda, if using nodejs runtime 14.x+, you are allowed to use ESM feature. Here is a post with more details about it. So, with ESM feature being available in lambda, if using the correct runtime, you can import the SDK by using the import keyword. However, there is a bug with lambda, when importing the v2 SDK, for which I have opened an internal ticket with correspondent team, but, we have a workaround that was suggested in the following StackOverflow blog post:

As you have worked out, the only workaround at present seems to be the use of absolute paths. E.g.:
import { DynamoDB } from 'aws-sdk;'
fails, whereas
import AWS from '/var/runtime/node_modules/aws-sdk/lib/aws.js';
const { DynamoDB } = AWS;
will work.

Here is the internal ticket for the bug I mentioned: V768775242.

So, if using the AWS SDK for JavaScript V3 then, you need to be on nodejs 18.x runtime, and with this SDK version the import works correctly.

Please let me know if you have any questions.

Thanks!

I just noticed this issue: aws/aws-lambda-base-images#71

If the SDK is still an older version, could that not cause some of the issues some of us are facing?

Still this issue.

Still, the issue is ongoing.
While nasty, this import works for me:
import AWS from '/var/runtime/node_modules/aws-sdk/lib/aws.js';

import AWS from '/var/runtime/node_modules/aws-sdk/lib/aws.js';

It is also not working .
I am using nodejs v18
any update?
why is this happening?

{
  "errorType": "Error",
  "errorMessage": "Cannot find module '/var/runtime/node_modules/aws-sdk/lib/aws.js' imported from /var/task/index.mjs",
  "trace": [
    "Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/var/runtime/node_modules/aws-sdk/lib/aws.js' imported from /var/task/index.mjs",
    "    at new NodeError (node:internal/errors:399:5)",
    "    at finalizeResolution (node:internal/modules/esm/resolve:331:11)",
    "    at moduleResolve (node:internal/modules/esm/resolve:994:10)",
    "    at moduleResolveWithNodePath (node:internal/modules/esm/resolve:938:12)",
    "    at defaultResolve (node:internal/modules/esm/resolve:1202:79)",
    "    at nextResolve (node:internal/modules/esm/loader:163:28)",
    "    at ESMLoader.resolve (node:internal/modules/esm/loader:838:30)",
    "    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:424:18)",
    "    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:77:40)",
    "    at link (node:internal/modules/esm/module_job:76:36)"
  ]
}

for node.js 18.x, these lines work for me. It needs some efforts but allows you to import only the features you need, reducing the size of the deployed code.
import { S3Client } from "@aws-sdk/client-s3";
import { ListObjectsV2Command } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client({ region: "us-west-2" });

I was only able to get this to work by downgrading to Node.js 16.x

import AWS from '/var/runtime/node_modules/aws-sdk/lib/aws.js';

Hello everyone on the thread,

The issue was opened against the v3 repo, however lots of the customers on that thread are experiencing difficulties with v2 so we will address both.

For v3: The solution is to use Lambda with Node 18. Imports for v3 are available from path.

For v2:
There is a lack of ES Modules support in Lambda Node 14 and 16, it affects all dependencies, not just the AWS SDK.
This is a limitation of Lambda, and is unrelated to the SDK and it is documented.

... by default Node.js does not search the folders in the NODE_PATH environment variable when importing ES modules. This makes it difficult to import ES modules from folders outside of the /var/task/ folder in which the function code is deployed. For example, to load the AWS SDK included in the runtime as an ES module, or to load ES modules from Lambda layers.

The Node.js 18.x runtime for Lambda searches the folders listed in NODE_PATH when loading ES modules. This makes it easier to include the AWS SDK as an ES module or load ES modules from Lambda layers.

There are currently 3 workarounds:

  • Use the Lambda Node 18 runtime and switch to JS SDK v3. The Node 18 runtime bundles the JS SDK v3 rather than v2, and does support importing ES modules from NODE_PATH. For more information, see Node.js 18.x runtime now available in AWS Lambda.

โ˜๏ธ This is the recommended workaround.
We are formalizing our plans to make the Maintenance Announcement (Phase 2) for AWS SDK for JavaScript v2 in 2023. For more info refer to our Maintenance Policy.
Additinally, Node 14 is already not in LTS, and Node 16 is scheduled for end of LTS during 2023.

  • With the Lambda Node 14 or Node 16 runtimes, you can deploy your own copy of the SDK v2 instead of using the SDK bundled with the runtime. This can be done by bundling the application, or providing the SDK in Lambda layer, or uploading your node_modules. By doing so, this places the SDK in a supported path, and you will then be able to import the SDK as an ES module.

  • Create a symlink to get the included SDK from the opt folder in Lambda. I have tested this solution myself, and verified that it's working.
    (not recommended)


Since there are many customers on here mentioning various problems on v2 and v3, it's difficult for us to analyze individual concerns on such a long thread. Once the issue is closed, it will not be monitored, so we might not see any future correspondence. Instead, if you are still experiencing difficulties, please open a new issue in the appropriate repo so we can assist you on a case-by-case basis.

We appreciate you all for engaging in the community and hope to hear from you again.

Thanks,
Ran~

In case someone wants to raise additional discussion points that we can talk about as a community, please post it here

Thanks,
Ran~

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.