aws / aws-sam-cli

CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM
https://aws.amazon.com/serverless/sam/
Apache License 2.0
6.47k stars 1.16k forks source link

VStudio Debug for Typescript Lambda function gives Runtime.ImportModuleError #7179

Open stib opened 2 weeks ago

stib commented 2 weeks ago

Description:

I did a sam init for out of the box Typescript Hello world sample. Runs fine when invoked locally but when I try to step into it through VS Debug I get the error below

{
    "errorType": "Runtime.ImportModuleError",
    "errorMessage": "Error: Cannot find module 'app'\nRequire stack:\n- /var/runtime/index.mjs",
    "stack": [
        "Runtime.ImportModuleError: Error: Cannot find module 'app'",
        "Require stack:",
        "- /var/runtime/index.mjs",
        "    at _loadUserApp (file:///var/runtime/index.mjs:1087:17)",
        "    at async Object.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"
    ]
}

Steps to reproduce:

  1. sam init to setup the project
  2. Pick the Hello World Typescript option
  3. Install all the packages through npm i
  4. sam build
  5. sam local invoke runs fine and gives the hello world message
  6. Update launch.json with following configuration
        {
            "type": "aws-sam",
            "request": "direct-invoke",
            "name": "TS hello test",
            "invokeTarget": {
                "target": "code",
                "lambdaHandler": "app.lambdaHandler",
                "projectRoot": "${workspaceFolder}/gt-lambda-ts/hello-world"
            },
            "lambda": {
                "runtime": "nodejs20.x"
            }
        }
  7. Set a breakpoint on the lambdaHandler in app.ts
  8. Invoke the "TS hello test" in VS
  9. Get the error above

Observed result:

Get the error above. Not sure what debug flag to set here since it is invoked through VS Code

Expected result:

The function is invoked and get to the breakpoint in lambdahandler

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

I am on Mac M1 Sonoma 14.5, SAM CLI, version 1.118.0, aws-cli/2.16.8 Python/3.11.8 Darwin/23.5.0 exe/x86_64 Visual Studio Code version 1.90.1

  1. OS: Mac M1 Sonoma 14.5
  2. sam --version: SAM CLI, version 1.118.0
  3. AWS region: us-west-2
# Paste the output of `sam --info` here

{ "version": "1.118.0", "system": { "python": "3.8.13", "os": "macOS-14.5-arm64-arm-64bit" }, "additional_dependencies": { "docker_engine": "26.1.1", "aws_cdk": "Not available", "terraform": "Not available" }, "available_beta_feature_env_vars": [ "SAM_CLI_BETA_FEATURES", "SAM_CLI_BETA_BUILD_PERFORMANCE", "SAM_CLI_BETA_TERRAFORM_SUPPORT", "SAM_CLI_BETA_RUST_CARGO_LAMBDA" ] }

mndeveci commented 2 weeks ago

Hi there,

Looking at the details, why are you running npm i in your lambda function? sam build should take care of building your lambda and installing your dependencies, npm i shouldn't be required. Can you try without running npm i?

Also, how did you create this debug configuration? It seems it is different than what VSCode gives as example when you try to run debug there. Can you test it with the debugging configuration which is generated by AWS Toolkits plugin in VSCode to see if it is going to work?

Thanks!

stib commented 2 weeks ago

Hi Mehmet,

Thank you for your note. I am new to SAM and didn't know that sam build would take care of installing any missing npm modules which sounds logical. Since I have already done that and sam local invoke works just fine on the TS hello-world function I am assuming I am all good there, independent of how npm i was called.

With respect to the debug configuration, I picked that from some example online and it works fine for the non Typescript (.mjs) hello-world lambda example I have so I am using the same structure for this Typescript example. I am not sure how to get VSCode to generate the debug configuration you are referring to for the TS hello-world lambda function. If you can point me to that (or post a sample) I can give it a try - I take it that is different from what I have. On that note, do you see something missing from the current debug configuration?

Also it is not clear why the error talks about index.mjs file (that I don't see anywhere) and the missing app module when it seems to be in the right place. It might have something to do with the fact that the transpiled file app.js is under the build directory in a different location and it might need some Typescript specific flag in the debug configuration but not sure if/what that may be.

Thank you for your help. Sanjay.

stib commented 2 weeks ago

Following the advice in this YT video I changed the configuration to that below below and was able to step into the code. However this seems like a round about way of doing so through another file.

However I am able to move forward here but had to do a local install of ts-node (otherwise I was getting an error that it didn't understand ts-node/register in config). Seems like there is probably a more direct and cleaner way - if so, would be happy to learn that.

        {
            "type": "node",
            "request": "launch",
            "name": "TS hello test",
            "runtimeArgs": [
                "-r",
                "ts-node/register"
            ],
            "args": [
                "${relativeFile}"
            ],
            "env": {
                "AWS_REGION": "us-west-2"
            }
        }
stib commented 2 weeks ago

I was having issues with reading a credential environment variable file with above configuration but while the code gets the filename passed through the GOOGLE_APPLICATION_CREDENTIALS envrionment variable below, it is not able to locate the file itself

{
            "type": "node",
            "request": "launch",
            "name": "TS hello test",
            "runtimeArgs": [
                "-r",
                "ts-node/register"
            ],
            "args": [
                "${relativeFile}"
            ],
            "env": {
                "projectRoot": "${workspaceFolder}/gt-lambda-ts/hello-world",
                "AWS_REGION": "us-west-2",
                "GOOGLE_APPLICATION_CREDENTIALS": "mycredentialfilename.json"
            }
        }

I get the error Error: Failed to read credentials from file <file name>

Code is trying to read credential through

import admin from 'firebase-admin';
...
credential = admin.credential.applicationDefault();

I added the projectRoot in the config above and also tried projectFolder attribute instead, with the file located directly under the gt-lambda-ts/hello-world directory but the code is unable to find and read that

To understand the configuration options better I looked up the configuration options here but I don't see any options as configured above e.g. I don't see "launch" as an option for "type" anywhere.

Issues I am trying to address -

  1. Where can I find reference for configuration options above?
  2. What change is needed for the configuration or Typescript code to be able to find the credential file set in the envrionment variable GOOGLE_APPLICATION_CREDENTIALS

Thank you for any pointers/help. Sanjay.

PS: I was debating whether to start a new issue on this but since it is related TypeScript Debug I decided to continue here. If CoC would be to start a new thread then please comment and I will do so. Thanks.

stib commented 2 weeks ago

For people running into the above issues, here are few things I found that may help.

As of today 6/24/24, SAM doesn't seem to support deployment of additional files that can be referenced through environment variables. So while I could get the local testing to work with absolute path to the file, SAM deploy doesn't include that credential file to deploy and if it does I don't know how/where. Feature request for this and additional details can be found here. To make it work in production unforutnately I had to include the credentials in the code itself.

There might be other solutions through CDK or Key management store that I haven't explored. If people know how that can be used here please feel free to comment. Otherwise this issue can be closed.

mndeveci commented 2 weeks ago

@stib

If these additional files are in the CodeUri folder of your function, then they will be included in the final build, hence in the deployment package. If you need them in multiple lambda functions, you can create a lambda layer with Makefile build to include those additional files, and you can reference this layer from other lambda functions to use them.

Please let us know if that helps with your deployment file problem.

stib commented 4 days ago

Thank you @mndeveci. I won't be able to test this for few weeks and since the Dev configuration setup, requiring full path to find the file, is different from prod setup that can take file in the same directory under CodeUri I won't be able to use it in the near future. I take it this will work as you suggest for Prod. If we can make it work in Dev as well without having to provide the full path in the configuration then that will be useful to move it to Prod.

I was going to close the issue with this comment but leaving it open in case you want to add further to it. Please feel free to close it out. Thank you for your responses.