TypeError: handler is not a function
tedyu opened this issue · 17 comments
Expected Behavior
datadog-lambda-js functions correctly with node.js 18.
Actual Behavior
TypeError: handler is not a function
anonymous at /opt/nodejs/node_modules/datadog-lambda-js/utils/handler.js, 150
Object.<anonymous> at /opt/nodejs/node_modules/datadog-lambda-js/index.js, 167
step at /opt/nodejs/node_modules/datadog-lambda-js/index.js, 44
Object.next at /opt/nodejs/node_modules/datadog-lambda-js/index.js, 25
anonymous at /opt/nodejs/node_modules/datadog-lambda-js/index.js, 19
new Promise at <anonymous>
__awaiter at /opt/nodejs/node_modules/datadog-lambda-js/index.js, 15
anonymous at /opt/nodejs/node_modules/datadog-lambda-js/index.js, 161
anonymous at /opt/nodejs/node_modules/dd-trace/packages/dd-trace/src/tracer.js, 94
anonymous at /opt/nodejs/node_modules/dd-trace/packages/dd-trace/src/tracer.js, 45
Steps to Reproduce the Problem
- "datadog-lambda-js": ">=6.89.0"
- node.js 18
Specifications
- Datadog Lambda Layer version:
- Node version: 18
Stacktrace
See above.
Hey @tedyu! Thanks for reaching out.
My guess is that you're seeing this error thrown from here which is loading your handler code.
We have to take your handler function and call it, if we can't load it, this error can result.
Can you check the value of DD_LAMBDA_HANDLER and verify that it correctly points to your function handler? If not, can you open a support ticket with us so that we can see your specific packaging logic and handler code, and identify any possible issues?
Thanks!
Can you confirm this is correct for node 18 ?
layers = ["arn:aws:lambda:${var.region}:464622532012:layer:Datadog-Node18-x:98"]
thanks
Hi, yes this is the right layer but you also need to configure your handler deployment correctly. I'm not sure which deployment tool you're using but you can find the instructions here.
At a glance, I think that DD_LAMBDA_HANDLER
is not being set correctly, so our layer can't load your code.
const { Datadog, datadog } = require('datadog-lambda-js');
...
async function handler(event) {
...
module.exports.handler = datadog(handler);
After wrapping the handler, I get the following:
TypeError: Cannot set property 'done' of undefined
at /opt/app/node_modules/datadog-lambda-js/dist/utils/handler.js:163:22
at /opt/app/node_modules/datadog-lambda-js/dist/index.js:223:70
at step (node_modules/datadog-lambda-js/dist/index.js:44:23)
at Object.next (node_modules/datadog-lambda-js/dist/index.js:25:53)
at /opt/app/node_modules/datadog-lambda-js/dist/index.js:19:71
at new Promise (<anonymous>)
Looking at utils/handler.js,
return function (event, context) {
It seems context is undefined.
Please let me know the proper way of wrapping.
@astuyve the link you mentioned, https://docs.datadoghq.com/serverless/aws_lambda/installation/nodejs/?tab=datadogcli, doesn't mention using wrapper.
Can you confirm whether wrapper is needed ? If so, what should be corrected in the formation in my previous comment ?
thanks
Hi!
Sorry! Those are just the entrypoint for our installation instructions.
Please select the installation method for your IAC provider using the tabs. We support most tools such as terraform, serverless framework, Sam, CDK, etc. It's okay if you're not using the datadogcli
method.
If you want to proceed with this via the custom instrumentation path, which is what it seems, you'll need to click the custom
tab: https://docs.datadoghq.com/serverless/aws_lambda/installation/nodejs/?tab=custom
If you want to use the custom
path but don't want to use the built-in handler redirection supported by this library, that's fine, you can wrap your function manually (as it seems you are attempting to do here).
That is linked further on the custom
page: https://docs.datadoghq.com/serverless/guide/handler_wrapper/
You may need to pass the implicit context
argument manually. It looks like that may be missing from the code snippet you've added (and perhaps the docs, although it should be passed automatically by the lambda runtime):
async function handler(event, context) {
I'd probably suggest trying the default handler redirection though, which means you don't need to touch this library in your own codebase but that's up to you.
Is this error present in Lambda, or coming from a local emulator?
Thanks!
I am upgrading code from node.js 14 to 18. I want to transform current code first to see if the upgrade can go through.
When I specify the context
parameter, I get:
/opt/app/lambda/index.js
79:31 error 'context' is defined but never used no-unused-vars
Can you tell me how context
should be passed down to datadog ?
Thanks
Hi, the context
object is passed by the runtime and documented by Lambda here.
If your linter is complaining about it, maybe you can use _context
as the variable name, or ignore the rule?
Thanks!
After suppressing the lint error, I still get:
TypeError: Cannot set property 'done' of undefined
at /opt/app/node_modules/datadog-lambda-js/dist/utils/handler.js:163:22
at /opt/app/node_modules/datadog-lambda-js/dist/index.js:223:70
at step (node_modules/datadog-lambda-js/dist/index.js:44:23)
at Object.next (node_modules/datadog-lambda-js/dist/index.js:25:53)
at /opt/app/node_modules/datadog-lambda-js/dist/index.js:19:71
at new Promise (<anonymous>)
at __awaiter (node_modules/datadog-lambda-js/dist/index.js:15:12)
at traceListenerOnWrap (node_modules/datadog-lambda-js/dist/index.js:200:36)
at /opt/app/node_modules/datadog-lambda-js/dist/index.js:246:91
It seems I need to find a way to pass down the context.
That path looks interesting, you're getting this error in Lambda, or coming from a local emulator?
Can you provide a minimal project which reproduces this?
Thanks!
The stack trace was copied from our circleci job which runs unit tests.
I will see if the reproduction can be isolated.
Meanwhile, it would be nice if someone can advise on passing context
parameter.
Thanks
Ahhhh I see! Thanks for that!
I had asked earlier if this error was being raised inside Lambda, but it's not.
This is occurring within a unit test, but you're exercising all of the features of this library outside of Lambda, which won't work.
You'll need to stub this library when testing it outside of Lambda (much like you would stub any normal external dependency). This library isn't meant to be executed without Lambda runtime features being present (nor will it run effectively without being able to reach the datadog agent or forwarder).
This is also why we support wrapping handlers via non-code paths, so that your unit tests can still run without this library being present.
I'm closing this issue as it's not an issue with this codebase.
Thank you!
I did some search w.r.t. stubbing out datadog handler for unit testing but haven't found answer.
If you can provide some pointer, that would be nice.
@astuyve
Another possibility is for datadog-lambda-js
to regard the absence of context
as indication that the lambda is not operating in normal cloud environment and return early.
This would make datadog-lambda-js
more developer friendly.
What do you think ?
Hi, you'll want to read the documentation for whatever test running library you're using. Jest or Mocha are both popular and offer this ability. You can even see how we do this with jest in this library.
This library isn't intended to be a development dependency, so we wouldn't even expect it to be installed outside of Lambda.
We would have to carefully consider how and where we'd return early here because we spy on the function entrance and exit, and it may be challenging to fully support a "disabled" mode.
Instead most users find they can stub this dependency easily and do so in their unit tests.
Thanks!
AJ
From https://github.com/DataDog/datadog-lambda-js, I see node 16 mentioned.
Can you confirm that node 18 is supported by 6.89 release ?
Thanks
Hi yes, we support node 18 as per the readme:
and all recent releases: https://github.com/DataDog/datadog-lambda-js/releases/tag/v7.99.0