Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Class extends value undefined is not a constructor or null #572

Open
AlanAlvarez5 opened this issue Aug 30, 2024 · 8 comments
Open

Class extends value undefined is not a constructor or null #572

AlanAlvarez5 opened this issue Aug 30, 2024 · 8 comments
Assignees

Comments

@AlanAlvarez5
Copy link

Expected Behavior

Normal flow, performing traces and regular behavior.

Actual Behavior

Throws error, before running lambda code. "Class extends value undefined is not a constructor or null"

Steps to Reproduce the Problem

  1. Use a serverless template with datadog-plugin
  2. Make a process with typeORM to perform CRUD operations at any database

Specifications

  • Serverless Framework version: 3
  • Datadog Serverless Plugin version: latest
  • Lambda function runtime (Python 3.7, Node 10, etc.): Node 20.x

Stacktrace

{
  "errorType": "TypeError",
  "errorMessage": "Class extends value undefined is not a constructor or null",
  "stack": [
      "TypeError: Class extends value undefined is not a constructor or null",
      "    at Object.<anonymous> (/opt/nodejs/node_modules/path-scurry/dist/commonjs/index.js:124:40)",
      "    at Module._compile (node:internal/modules/cjs/loader:1358:14)",
      "    at Module._extensions..js (node:internal/modules/cjs/loader:1416:10)",
      "    at Module.load (node:internal/modules/cjs/loader:1208:32)",
      "    at Module._load (node:internal/modules/cjs/loader:1024:12)",
      "    at Module.require (node:internal/modules/cjs/loader:1233:19)",
      "    at Hook.Module.require (/opt/nodejs/node_modules/dd-trace/packages/dd-trace/src/ritm.js:97:33)",
      "    at require (node:internal/modules/helpers:179:18)",
      "    at Object.<anonymous> (/opt/nodejs/node_modules/glob/dist/commonjs/glob.js:6:23)",
      "    at Module._compile (node:internal/modules/cjs/loader:1358:14)"
  ]
}
@AlanAlvarez5
Copy link
Author

Hello, I already found the issue reason

I have installed the leatest version of typeorm ("typeorm": "^0.3.20") and I have to downgrade to "typeorm": "0.3.17" in order to resolve the error.

I hope you can close the issue soon. Thanks

@purple4reina
Copy link
Contributor

Hi @AlanAlvarez5 Thanks for reporting this issue. I appreciate the work you've put into it already. I'm taking a look now and we'll get this released soon.

@purple4reina
Copy link
Contributor

Hey @AlanAlvarez5 I haven't yet been able to reproduce the stacktrace. Can you share your code where you're initializing your db connection using typeorm at the global level?

@AlanAlvarez5
Copy link
Author

Hello!

This is de datadog serverless plugin config

datadog: {
    enabled: true,
    site: "site",
    enableXrayTracing: false,
    enableDDTracing: true,
    enableDDLogs: true,
    captureLambdaPayload: true,
    env: "env",
    service: "serviceName"
    apiKeySecretArn: "apiKeySecretArn"
  }

This is the typeorm client init config

// Database Client Class 
async init (): Promise<void> {
    if ( !this.connection ) {
      const options = await this.buildDataSourceOptions();
      this.connection = new DataSource( options );
    }

    if ( !this.connection.isInitialized ) {
      await this.connection.initialize();
    }
  }

Additionally, I'm using inversify to make de dependency injection, and my database client is configured in singleton scope.

Also, the version of serverless framework is 3.25.

Hope you can replicate the stacktrace. Let me know y you need anything else.

@purple4reina
Copy link
Contributor

Hi again @AlanAlvarez5,

I spent a good deal of time looking into this issue. The cause is definitely not related to this repo, the serverless-plugin-datadog since the plugin code only runs on deploy, not on invocation. Instead, I suspect there is a circular dependency somewhere between your versions of glob, lru-cache, and path-scurry.

Searching for the specific error you're hitting leads to this stackoverflow question which explains the most common cause for this error is circular dependencies. Since downgrading your version of typeorm solved the issue, I suspect this is indeed your cause.

Next steps for you are to first confirm my belief that this error is not datadog related. Redeploy your lambda function, removing all datadog instrumentation, specifically dd-trace-js. If you are still seeing the error, which I suspect you will, then datadog has nothing to do with it. If for some reason removing datadog and invoking your function does not error, then I would next like to see your package.json and package-lock.json.

After that, you will need to track down exactly where the circular dependency is coming from. You'll want to use the stacktrace you shared above to open the specific files in your node_modules directory and trace the calls. Since I do not know which versions of all your dependencies you are using, I can't do this for you. From your stacktrace, we can see that glob is first imported. During this import, on line 6 of the glob code, it then attempts to import another package, path-scurry. While attempting to import path-scurry, you're seeing this error. But again, I do not now which specific versions you are using of all these packages, so I cannot find for you where the circular dependency is.

From there, you'll want to post this question to one of the packages that is involved in the circular dependency, I suspect this will be either glob or path-scurry, but I'm not sure.

Hope this helps.

@AlanAlvarez5
Copy link
Author

Hello, I already done that.

Actually I have been working with the "typeorm": "^0.3.20" on my repo before datadog configuration. And after that, for several weeks it worked just fine. Suddenly, it sttoped to work and we thought It would be related with the circular dependency. We spent some time triying to refactor and change some imports untill we relized the issue comes with the dd plugin.

I disabled datadog plugin and packages in this ways:

  • Configure datadog plugin prop enable to false. My lambda worked fine.
  • Remove datadog layers and all packages from the package json: My lambda worked fine.

Only with the plugin enabled throws error.

I can share you the packages of my package json but, I do not have declared glob or path-scurry package.

"@aws-sdk/client-dynamodb": "^3.614.0", "@aws-sdk/client-s3": "^3.614.0", "@aws-sdk/client-secrets-manager": "^3.614.0", "@middy/core": "^3.4.0", "@middy/http-json-body-parser": "^3.4.0", "axios": "^1.7.3", "form-data": "^4.0.0", "inversify": "^6.0.2", "joi": "^17.13.3", "jsonwebtoken": "^9.0.2", "mssql": "^11.0.1", "mustache": "^4.2.0", "pg": "^8.12.0", "reflect-metadata": "^0.2.2", "typeorm": "0.3.17", "uuid": "^10.0.0"

@purple4reina
Copy link
Contributor

Okay, thank you for that detailed explanation, that does indeed indicate that the issue is somewhere with the datadog instrumentation. Apologies for taking us off course.

I am going to move this issue to the datadog-lambda-js repo. I'm not 100% certain that's where the bug is, but it's at least closer. I'll keep looking into this once it's moved.

Since I haven't yet been able to reproduce this, are you able to create a small lambda function that does? If I can get a handler.js file along with the package*.json files, then I'll be able to track this down a whole lot faster.

Let me know if you discover anything else in the meantime.

@purple4reina purple4reina transferred this issue from DataDog/serverless-plugin-datadog Sep 4, 2024
@purple4reina
Copy link
Contributor

Hey @AlanAlvarez5,

I have an update for you. I spoke with the team and we think this issue might be caused by dependency collisions when using lambda layers.

I assume the collision is happening with lru-cache, so let's look at it more closely. dd-trace requires lru-cache version ^7.14.0 whereas typeorm requires glob which requires path-scurry which requires lru-cache version ^10.2.0.

I assume you are uploading the dependencies by including the node_modules in your lambda package zip. When aws installs this code in the lambda container, it does so at /var/task, meaning you'll find lru-cache version ^10.2.0 at /var/task/node_modules/lru_cache. Next comes the lambda layers, which includes the datadog layer and dependencies. These get installed at /opt, meaning you'll find lru-cache version ^7.14.0 at /opt/node_modules/lru_cache.

Finally it is time to execute your function. When resolving dependencies, the runtime looks in /var/task first and if not found there will go search in /opt next. Since dd-trace works by hooking into the import system, the second you import anything, dd-trace is called which needs lru-cache. But instead of finding version ^7.14.0 in /opt, version ^10.2.0 is instead found first at /var/task and therefore used. This leads to the error you are getting.

I suspect the reason why downgrading typeorm fixes things is because version 0.3.17 requires a lower version of lru-cache than 0.3.20 does and dd-trace works fine with this lower version.

So what do you do about this? Stop using the Datadog lambda layer and instead install the Datadog dependencies yourself alongside all your other dependencies. To do so, you will instruct the Datadog plugin not to install the layer by including this in your serverless.yml file:

custom:
  datadog:
    addLayers: false

Then, include datadog-lambda-js in your package.json file as a dependency and redeploy.

Let me know how this works out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants