Why do I get a UserCodeSyntaxError when I have no syntax error in my code? - node.js

I'm currently creating a Dialogflow chatbot in nodejs and upon deploying my code I get an error message. I've attempted to uncomment most things out to just be left with the base functioning code and I am still unable to get it working. I'm not exactly sure what the issue is here
'use strict';
import {getAPIresponse} from "./api/index.js";
// const http = require('https');
// const respond = fulfillmentText => {
// return {
// statusCode: 200,
// body: JSON.stringify({
// fulfillmentText
// }),
// headers: {
// "Content-Type": "application/json"
// }
// }
//
// };
module.exports.dining = async (event,context) => {
const incoming= JSON.parse(event.body).queryResult;
console.log(`INCOMING: ${incoming.parameters.hall}`);
const {
displayName
} = incoming.intent;
console.log(displayName);
//const menu = getAPIresponse('https://esb.prod.uds.harvard.edu/api/dining/2.0/','events?locationId=36');
//console.log(menu);
// if(displayName === 'dining'){
// if(incoming.parameters.meal === 'breakfast'){
// //get's dining hall code to include in API request
// const hall = getCode(incoming.parameters.hall);
// //generate response from API based off of parameters passed by user
// const menu = getAPIresponse("https://esb.prod.uds.harvard.edu/api/dining/2.0/","events?locationId=${hall}", hall);
// console.log(menu);
// }
// if(incoming.parameters.meal === 'lunch'){
// //get's dining hall code to include in API request
// const hall = getCode(incoming.parameters.hall);
// //generate response from API based off of parameters passed by user
// const menu = getAPIresponse("https://esb.prod.uds.harvard.edu/api/dining/2.0","/events", hall);
// }
// if(incoming.parameters.meal === 'dinner'){
// //get's dining hall code to include in API request
// const hall = getCode(incoming.parameters.hall);
// //generate response from API based off of parameters passed by user
// const menu = getAPIresponse("https://esb.prod.uds.harvard.edu/api/dining/2.0","/events", hall);
// }
// }
};
Almost everything is commented out and I still get the error message that reads
2019-07-02 16:31:33.351 (-04:00) undefined ERROR Uncaught Exception {
"errorType":"Runtime.UserCodeSyntaxError","errorMessage":"SyntaxError: Unexpected tok
en {","stack":["Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token {"," at
_loadUserApp (/var/runtime/UserFunction.js:98:13)"," at Object.module.exports.loa
d (/var/runtime/UserFunction.js:140:17)"," at Object.<anonymous> (/var/runtime/ind
ex.js:36:30)"," at Module._compile (internal/modules/cjs/loader.js:701:30)"," a
t Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)"," at Modu
le.load (internal/modules/cjs/loader.js:600:32)"," at tryModuleLoad (internal/modu
les/cjs/loader.js:539:12)"," at Function.Module._load (internal/modules/cjs/loader
.js:531:3)"," at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)",
" at startup (internal/bootstrap/node.js:283:19)"]}

Worked for me: Updating Node.js version of lambda
I got this error because lambda was defined to execute with Node.js 12.x, when I changed it to Node.js 14.x (as on my local machine) it worked
If it works - and you're generally using the serverless package to automate the deployment of your lambda - don't forget to update your serverless.yml file accordingly

AWS Lambda does not support the ES6 import specifier as you've written here
import {getAPIresponse} from "./api/index.js";
because the ES6 import syntax isn't yet supported by default in Node.js (note: my lambda runtime was set to Node.js 10.x).
Illustration:
I was having this issue as well when importing a library at the top of my lambda distribution's index.js file.
The stacktrace Uncaught Exception { "errorType":"Runtime.UserCodeSyntaxError", ... unexpected token import found ... blabla... } ... was thrown in my lambda function when I used the import syntax:
import awsServerlessExpress from 'aws-serverless-express';
exports.handler = (event, context) => {
console.log('hello world!')
};
But not in this version below when I just used the standard module require syntax.
const awsServerlessExpress = require('aws-serverless-express');
exports.handler = (event, context) => {
console.log('hello world!')
};
For me, it was the import syntax that was causing the SyntaxError exceptions, but do take note that, for you, any JavaScript syntax not supported by your current Node.js runtime will throw this exception.
A couple of solutions:
Change all import statements to standard module require statements and keep using whatever default JavaScript flavour is supported by your configured Node.js runtime.
Use a transpiler like Babel w/ Webpack to transpile your ES6 JavaScript before deploying to the cloud.
Use the quick solution nicely described by Yitzchak below :) Just bump the NodeJS version on your Lambda Dashboard.

In my case, I pasted code from another lambda which had node version 14.
But my current lambda node version was 12.
The code I pasted was using optional chaining(?.) in one line. Removed it, deployed code and it worked fine.

If you are using TypeScript and encounter this error make sure the target you set in tsconfig.json matches your targeted nodejs version. For a list of recommended settings visit Node Target Mapping
For example I was targeting node.js 12 and using ES2020. Changing this to ES2019 fixed my issue.

Sometimes in lambda, when we click on Deploy all the changes are not deployed. Refresh the page and check for syntax errors.
or at least that's what was the problem in my case.

In my case I changed the tsconfig.json module setting:
"module": "es2015"
to
"module": "CommonJS",
ref: https://www.typescriptlang.org/tsconfig#module

Related

Why isn't my Node package being imported?

I'm learning Node.js and am using a Node-based Azure Function.
I'm trying to bring in Chalk, to log coloured messages to the console.
However, all of the below fail (in my main index.js file).
One
module.exports = async (ctx, req) => {
const chalk = require('chalk');
return console.log(chalk.blue('Hello world!'));
Despite being the approach recommended in this answer, this results in a console error that says:
Exception: require() of ES Module C:...\node_modules\chalk\source\index.js from C:...\index.js not supported.
Instead change the require of C:...\chalk\source\index.js in C:...\index.js to a dynamic import() which is available in all CommonJS modules.
Two
If I do as the error suggests, and use
const chalk = async import('chalk')
...I then get
Exception: chalk.blue is not a function
...even though console.log(chalk) does seem to show the Chalk API and its various properties.
Three
The Chalk docs themselves recommend this:
module.exports = async (ctx, req) => {
import chalk from 'chalk'
return console.log(chalk.blue('Hello world!'));
That yields an error saying I can't use import outside of a module (but surely I'm in one?)
Four
Same as three ^^ but moving the import outside module.exports:
import chalk from 'chalk'
module.exports = async (ctx, req) => {
return console.log(chalk.blue('Hello world!'));
...yields the same error.
I'm sure this is a basic error but I can't find what I'm doing wrong so I'd be so grateful if someone could help. Thank you!
When you import something using import as a function(lazy import), It'll return an object with a default property and all exported properties. That you should use to access the module.
const module = async import('chalk')
const chalk = module.default
console.log(chalk.red('Hello world!'))

Using serverless deployment to lambda with ES6 /Node.js v16

Newbie question....
I have a locally working node.js application which I am now trying to deploy express to AWS lambda. I have used this guide to deploy a test version (which worked).
I now am trying to implement my application which uses ES6 (and has type: module in package.json).
In my application I have added
import serverless from 'serverless-http'
but I cannot figure out the appropriate syntax for the export - the original was...
module.exports.handler = serverless(app);
I have tried:
const handler = async (app) =\> {
return serverless(app)
}
export default handler
Error message received:
2022-11-05T15:50:25.962Z undefined ERROR Uncaught Exception
"errorType": "Runtime.HandlerNotFound",
"errorMessage": "app.handler is undefined or not exported",
"stack": [
"Runtime.HandlerNotFound: app.handler is undefined or not exported",
" at Object.UserFunction.js.module.exports.load (file:///var/runtime/index.mjs:979:15)",
" at async start (file:///var/runtime/index.mjs:1137:23)",
" at async file:///var/runtime/index.mjs:1143:1"
]
I strongly suspect I am missing some fundamental understanding - truly appreciate some guidance.
The reason for the error is that you are sending a default export when AWS Lambda is expecting a named export.
The issue is the same as with all ES6 imports/exports:
// export.js
export default const defaultExport = "foo"
export const namedExport = "bar"
// import.js
import { defaultExport } from "./export.js" // error, cannot find defaultExport
import { namedExport } from "./export.js" // success, found namedExport
import defaultExport from "./export.js" // success, found defaultExport
So, it's like the case above where you're sending the defaultExport, but AWS Lambda wants the { namedExport }. You just need to remove default from your export, and make sure you're building the handler properly. Here is a suggestion to do that:
const lambda = serverless(app)
export async function handler(event, context) {
return lambda(event, context)
}
I've tested and it's working with serverless-offline using Node18.x. You can read more about exports on MDN.

Cannot use import statement outside a module in Lambda function

I have created a lambda function to get the list of items stored in dynamodb. Then i executed npm run build command after which i got .js files. I zipped the dist contents along with node modules, webpack.config.js and package.json and uploaded it. When i try to test it, am getting the following error. But there is no error in the code as far as i checked.
{
"errorType": "Runtime.UserCodeSyntaxError",
"errorMessage": "SyntaxError: Cannot use import statement outside a module",
"trace": [
"Runtime.UserCodeSyntaxError: SyntaxError: Cannot use import statement outside a module",
" at _loadUserApp (/var/runtime/UserFunction.js:98:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
" at Object.<anonymous> (/var/runtime/index.js:43:30)",
" at Module._compile (internal/modules/cjs/loader.js:956:30)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)",
" at Module.load (internal/modules/cjs/loader.js:812:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:724:14)",
" at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)",
" at internal/main/run_main_module.js:17:11"
]
}
I had the same error with node uuid module. Importing and using it as below fixed my issue:
'use strict';
const uuid = require('uuid'); // <-- how to import
exports.hello = async (event) => {
// ...
uniqueId = uuid.v4(); // <-- how to use it
// ...
};
I was ok with using require() for the longest time BUT certain packages like netlify cannot be loaded in lambda via require().
But AWS improved this ES vs commonJS import statement support early 2022... See here. Sadly not well described.
The following steps are maybe not perfect but worked for me:
Switch to NodeJs v14 on your AWS function if you didn't already
Pack the packages that you want to use once more and don't just have a nodejs folder but also a node14 folder. The node14 folder is mentioned here and I think essential. In case you forgot how to create lambda packages follow the docs here.
Create a lib.mjs file and load the package via import from /opt/nodejs/node14/node_modules/[my-package]/[maybe-some-subfolder]/index.js.
You can export what you need as object from lib.mjs and load it from index.js
lib.mjs:
// lib.mjs
import { NetlifyAPI } from "/opt/nodejs/node14/node_modules/netlify/src/index.js";
import { Route53Client } from "/opt/nodejs/node14/node_modules/#aws-sdk/client-route-53/dist-cjs/index.js";
export function loadPackages() {
return { NetlifyAPI, Route53Client };
}
Index.js:
//index.js:
import { loadPackages } from './lib.mjs';
export async function handler(event) {
const { NetlifyAPI, Route53Client } = loadPackages();
//TODO: business logic
}
This took me a long time to research and my approach is likely not perfect. I was forced to find a solution to load netflify and it only worked via import statement. I'm happy to get feedback in the comments and I am willing to adjust my tutorial accordingly.
Currently I'd generally still recommend to stick with require() if you can. If not I hope I could help.
PS: webpack is not needed in this approach.
This might be pretty late but i fixed mine by using require instead of import when importing modules
You have a problem with your import. Review your code (imports parts) and see if your IDE detects any errors. For my case, it was :
import Jimp from 'jimp/es'
I changed it to
import Jimp from 'jimp'
And now everything works.

Requested module does not provide an export?

First post here, be gentle :)
I'm in the process of learning a bit of node.js and I'm trying to do some stuff with a module called 'node-bom'
I am familiar with the 'require' method for calling node modules. However the author has provided the following code example, which doesn't work with node.js:
import {Bom} from 'node-bom'
const bom = new Bom({
/// options
})
bom.getParsedStateData('VIC', {
bypassCache: false // default: false to use cache
})
.then((stateData) => {
console.log(stateData)
/*
{
forecast: {}, // forecast data
observations: {} // current station's observations data
}
*/
})
This code produces the following error:
(node:10363) ExperimentalWarning: The ESM module loader is experimental.
file:///Users/ajudge/node-bom-testing/index.mjs:1
import {Bom} from 'node-bom'
^^^
SyntaxError: The requested module 'node-bom' does not provide an export named 'Bom'
at ModuleJob._instantiate (internal/modules/esm/module_job.js:93:21)
at async ModuleJob.run (internal/modules/esm/module_job.js:108:20)
at async Loader.import (internal/modules/esm/loader.js:128:24)
I've done some further reading and this appears to be an ES6 issue. So, I have changing the file to a .mjs and using the --experimental-modules flag, but I'm still not having any luck.
Can anyone clarify what I need to modify to get this module to work?
Thanks!
Change your filename to .js
The example in the package docs is more TypeScript oriented (hence the import).
In Node.JS your code should look like:
const Bom = require('node-bom')
const bom = new Bom.Bom({
/// options
})
bom.getParsedStateData('VIC', {
bypassCache: false // default: false to use cache
})
.then((stateData) => {
console.log(stateData)
/*
{
forecast: {}, // forecast data
observations: {} // current station's observations data
}
*/
})

Error:"Failed to get the current sub/segment from the context" when use AWS X-ray in Lambda with node.js

I am trying to use implement the AWS X-ray into my current project (using Node.js and Serverless framework). I am trying to wire the X-ray to one of my lambda function, I got the problem of
Error: Failed to get the current sub/segment from the context.
at Object.contextMissingRuntimeError [as contextMissing] (/.../node_modules/aws-xray-sdk-core/lib/context_utils.js:21:15)
at Object.getSegment (/.../node_modules/aws-xray-sdk-core/lib/context_utils.js:92:45)
at Object.resolveSegment (/.../node_modules/aws-xray-sdk-core/lib/context_utils.js:73:19).....
code below:
import { DynamoDB } from "aws-sdk";
import AWSXRay from 'aws-xray-sdk';
export const handler = async (event, context, callback) => {
const dynamo = new DynamoDB.DocumentClient({
service: new DynamoDB({ region })
});
AWSXRay.captureAWSClient(dynamo.service);
try {
// call dynamoDB function
} catch(err) {
//...
}
}
for this problem, I use the solution from
https://forums.aws.amazon.com/thread.jspa?messageID=821510&#821510
the other solution I tried is from https://forums.aws.amazon.com/thread.jspa?messageID=829923&#829923
code is like
import AWSXRay from 'aws-xray-sdk';
const AWS = AWSXRay.captureAWS(require('aws-sdk'));
export const handler = async (event, context, callback) => {
const dynamo = new AWS.DynamoDB.DocumentClient({region});
//....
}
Still not working...
Appreciated to the help of any kind.
As you mention, that happened because you're running locally (using serverless-offline plugin) and the serverless-offline plugin doesn't provide a valid XRAY context.
One possible way to pass this error and still be able to call your function locally is setting AWS_XRAY_CONTEXT_MISSING environment variable to LOG_ERROR instead of RUNTIME_ERROR (default).
Something like:
serverless invoke local -f functionName -e AWS_XRAY_CONTEXT_MISSING=LOG_ERROR
I didn't test this using serverless framework but it worked when the same error occurred calling an amplify function locally:
amplify function invoke <function-name>
I encountered this error also. To fix it, I disabled XRay when running locally. XRay isn't needed when running locally because I can just set up debug log statements at that time.
This is what the code would look like
let AWS = require('aws-sdk');
if (!process.env.IS_OFFLINE) {
const AWSXRay = require('aws-xray-sdk');
AWS = AWSXRay.captureAWS(require('aws-sdk'));
}
If you don't like this approach, you can set up a contextStrategy to not error out when the context is missing.
Link here
AWSXRay.setContextMissingStrategy("LOG_ERROR");
If you don't want the error clogging up your output you can add a helper that ignores only that error.
// Removes noisy Error: Failed to get the current sub/segment from the context due to Xray
export async function disableXrayError() {
console.error = jest.fn((err) => {
if (err.message.includes("Failed to get the current sub/segment from the context")) {
return;
} else {
console.error(err);
}
});
}

Resources