Why can't try catch work for some exceptions? - node.js

I have below code in a nodejs application. The createUserWithEmailAndPassword is used to create a user in firebase service. The problem is that the try catch doesn't work if there is an exception which is thrown from the method createUserWithEmailAndPassword and it crashes my application. I wonder what the way to catch all errors in nodejs. Why doesn't try catch work in my case?
try {
return firebase
.auth()
.createUserWithEmailAndPassword(email, password);
} catch (err) {
l.error(err);
return reject(err);
}

If your methods are promise implemented then in that case you dont need to use try-catch block. take look at below sample code to achieve desire output.
let assume your method called auth or createUserWithEmailAndPassword are promise implemented as below. do same for auth
function createUserWithEmailAndPassword(param1,param2){
return Promise(function(reject,resolve){
//your code here
})
}
then to call this method in such way that you can able to handle in exception/errors
return firebase
.then(function(result){
return auth();
})
.then(function(result){
return createUserWithEmailAndPassword(email, password);
})
.then(function(result){
//on success
resolve(result)
})
.catch(function(err){
//handle all errors here
reject(err)
})

Related

How to handle UnhandledPromiseRejectionWarning

This bit of code, after connecting, does some stuff
controller.connect((response)=>{ does some stuff })
Down deep in the guts of the connect method this async function gets called, which returns a promise by way of the callback
async function ServerSend(endpoint,params,callback) {
const response = axios.get(host+endpoint, {params})
callback(response);
}
If the server is not available it correctly throws: UnhandledPromiseRejectionWarning: Error: connect ECONNREFUSED 127.0.0.1:8088
What is the correct way to handle this exception? I could possibly add a catch in the async method and rewrite all the call backs to return an err. But I'd rather catch it at the caller. I have not been able to get either method to work.
axios.get(host+endpoint, {params}) // this is a promise
so if it resolves it will be ok, but if it rejects (and yuou dont have any try .. catch, any .catch attached - it will throw error that exception is unhandled.
Why way would be to:
async function ServerSend(endpoint,params,callback) {
try {
const response = await axios.get(host+endpoint, {params})
callback(null, response);
} catch (err) {
callback(err, null);
}
}
OR
function ServerSend(endpoint,params,callback) {
// most callbacks are two parameters - 1st erro or null, second data if no error is present.
axios.get(host+endpoint, {params}).then(data => callback(null, data)).catch(err => callback(err, null));
}

How to completely ignore permission errors in Discord.JS?

How can I ignore all bot's permission errors in Discord.JS? I have already the checking bot's permissions functions, but this function doesn't work on the channels permissions. You can answer how can I ignore all bot's permission errors (if it can) or how to check permissions even in the channels permissions.
There is my error (it's the same as not checking permissions):
throw new DiscordAPIError(data, res.status, request);
^
DiscordAPIError: Missing Permissions
You can check GuildMember#permissions to see if the client has a certain permission in a guild.
// Example
const botMember = message.guild.me;
if (!botMember.permissions.has('KICK_MEMBERS')) {
// Code
} else {
// Error Handling
}
Additionally, you can use GuildMember#permissionsIn() to check the client's permissions in a certain channel
const botMember = message.guild.me;
if (!botMember.permissionsIn(CHANNEL).has('permission')) {
// Code
} else {
// Error Handling
}
As shown in other answers, you can also handle the promise rejection using .catch() or catch () {}
Ensure you're awaiting any promise function when using async/await + try/catch
// Example
try {
await message.channel.send(...);
} catch (err) {
// Handle err
}
message.channel.send(...)
.then(msg => {})
.catch(err => {
// Handle err
});
You could solve this in multiple ways
Wrap it in a try/catch statement
This would look something like:
try{
// Do this
} catch (error) {
// Do that
}
You caould use a .catch() function
role.doSomething().catch((error) => {
// Do that
})
If you wanted to see if the error code was due to a missing permission you could do:
const { Constants } = require("discord.js")
try{
// Do this
} catch (error) {
// Do that
if(error.code === Constants.APIErrors.MISSING_PERMISSIONS){
// Do this and that
}
}
You could try exception handling, if you're just wanting the bot to proceed without crashing it.
I would recommend at least logging the error in console. For this example I'll use a try/catch block.
try{
await doSomethingThatRequiresPermissions();
}catch(error){
console.log("Error: "+error+" at doSomethingThatRequiresPermissions");
}
NodeJS error handling documentation
Discord.js specific permission handling
Edit: I don't have access to my server at the moment (as I'm at work) but I will test this later to find a more comprehensive answer.

Module sending back api data

I'm working on a module containing a class with functions which calls an api everytimes we use a function.
I want to handle the result & catch IN the module and only send data in return.
function getAllFromTable(aTableName){
const request = {
.... aTableName
}
return apiCall(request)
}
function apiCall(requestConfig){
axios(requestConfig).then(result => {
return result.data
}
.catch(err => {
return err
}
}
That's the idea of what I would like to do but of course this only sends back "undefined"..
Is there a way to make a return in a then() to send back the data ?
Or another way to send back only the data and not a Promise to the one who calls the function "getAllFromTable()" ?
Is there a way to make a return in a then() to send back the data ? Or another way to send back only the data and not a Promise to the one who calls the function "getAllFromTable()" ?
No. In Javascript, there is NO way to return an asynchronously retrieved result directly. You HAVE to use an asynchronous mechanism such as a promise, a callback or an event to communicate back the asynchronous result. Since you already have a promise, you need to just return the promise and make sure that its resolved value is your final result. Then, the caller can use either .then() or await to get the result out of the promise.
That's the idea of what I would like to do but of course this only sends back "undefined"..
In your apiCall() function, you have to return the promise and fix your error handling.
Change this:
function apiCall(requestConfig){
axios(requestConfig).then(result => {
return result.data
}.catch(err => {
return err
});
}
to this:
function apiCall(requestConfig){
return axios(requestConfig).then(result => {
return result.data;
});
}
I removed the .catch() because you were changing the promise from rejected to resolved and making the error object be the resolved value. That is unlikely what you want for the function behavior and very unlikely what the caller wants. If you want a .catch() to log the error or something, then you can throw the error again to make sure the promise stays rejected.
function apiCall(requestConfig){
return axios(requestConfig).then(result => {
return result.data;
}).catch(err => {
// log error and rethrow so the promise stays rejected
console.log(err);
throw err;
});
}
The caller of apiCall() will then either use .then() or await to get the resolved value of the promise that the function returns.
apiCall(...).then(val => {
console.log(val);
}).catch(err => {
console.log(err);
});

How to catch errors thrown in node.js aws-sdk functions

I'm using aws-sdk module in node.js, and am attempting to validate a config object which contains a profile parameter (sent as a string and used to construct a SharedIniFileCredentials object) and a region.
To validate the sent region, I will create an ec2 object using a known region, and the profile parameter provided above and then check if the region paramter is found in the result of ec2.describeRegions.
I'd like to validate the profile parameter by catching any exceptions thrown executing the above, and am trying this with the setup below:
var aws = require('aws-sdk'); // aws sdk
var creds = new aws.SharedIniFileCredentials({profile: profile});
var conf = new aws.Config({
"credentials": creds,
"region": "eu-west-1" //Known region
});
var ec2 = new aws.EC2(conf);
try {
ec2.describeRegions({}, function (err, data) {
if (err) throw new Error(err.message);
//Do stuff below to check if region is found in data.Regions array
//...
// If not found -> errorCallback();
successCallback();
});
} catch(err){
errorCallback();
}
It seems that when the profile is invalid, err.message is correctly coming out as:
CredentialsError: Missing credentials in config, if using AWS_CONFIG_FILE, set AWS_SDK_LOAD_CONFIG=1
but instead of catching the error constructed from this, the error is unhandled and kills the process:
C:\workspaces\njw\node_modules\aws-sdk\lib\request.js:31
throw err;
^
Error: Missing credentials in config, if using AWS_CONFIG_FILE, set
AWS_SDK_LOAD_CONFIG=1
at Response. (C:\workspaces\njw\test.js:69:24)
at Request. (C:\workspaces\njw\node_modules\aws-sdk\lib\request.js:364:18)
If I don't throw the error inside the describeRegions callback, it will be correctly handled by the catch clause. Any idea why this isn't working inside the callback?
The problem here is the scope of try/catch block.
Apart from successCallback and errorCallback are not defined in your example and assuming they are valid in our scope and their meaning are the callbacks of a function, this block
try {
ec2.describeRegions({}, function (err, data) {
if (err) throw new Error(err.message);
successCallback();
});
} catch(err){
errorCallback();
}
is equivalent to this one
function responseHandler(err, data) {
if (err) throw new Error(err.message);
successCallback();
}
try {
ec2.describeRegions({}, responseHandler);
} catch(err){
errorCallback();
}
and the thrown Error is not in not in a try/catch block.
Errors returned from asynchronous function accepting callback (this is not a aws-sdk specific) usually are handled returning the error to caller callback, something like:
function myAsyncCheck(done) {
ec2.describeRegions({}, (err, data) => {
if (err) return done(err);
let result, something_bad;
//Do checks for something bad accordingly the logic you need
if(something_bad) return done(new Error("Something bad"));
// Do other stuff to set result
done(null, result);
});
});
or, if you need to call ec2.describeRegions in global scope and successCallback and errorCallback are functions in global scope, probably you need to change errorCallback in order to accept an error as parameter, otherwise you can't get error details, but this is really an ugly design pattern.
var ec2 = new aws.EC2(conf);
ec2.describeRegions({}, (err, data) => {
if (err) return errorCallback(err);
//Do checks for something bad accordingly the logic you need
if(something_bad) return errorCallback(new Error("Something bad"));
successCallback();
});
Hope this helps.

NodeJS mailparser not being executed

I am new to NodeJS. The following code snippet from my script is not executing nor it is logging any errors.
console.log('Process attachment');
const simpleParser = require('mailparser').simpleParser;
console.log('Process attachment');
simpleParser(data.Body, (err, mail) => {
if (err) {
console.log('attachment error');
console.log(err)
callback(null, null);
} else {
console.log('attachment success');
console.log(mail)
console.log(mail.attachments[0])
console.log(mail.attachments[0].content)
console.log(mail.attachments[0].content.toString('ascii'))
callback(null, null);
}
})
console.log('Exit');
process.exit();
Process attachment and Exit are being logged in the console but for some reason the code never goes in either the if or the else. So it looks like the simpleParser function is not being executed for some reason. data.Body contains a full email body. Is there anything obvious i am missing ? Thanks.
Why don't you use promises instead ?
This will work
simpleParser(data.Body).then(mail=>{
console.log('attachment success');
console.log(mail)
console.log(mail.attachments[0])
console.log(mail.attachments[0].content)
console.log(mail.attachments[0].content.toString('ascii'))
}).then(()=>{
console.log('Exit');
process.exit();
}).catch(err=>{
console.log('attachment error');
console.log(err);
})
And if you want to make it look simpler, cleaner use Async/Await like this
const parseMail = async ()=>{
try {
let mail = await simpleParser(data.Body);
console.log('attachment success');
console.log(mail)
console.log(mail.attachments[0])
console.log(mail.attachments[0].content)
console.log(mail.attachments[0].content.toString('ascii'))
}
catch(err) {
console.log('attachment error');
console.log(err);
}
console.log('Exit');
process.exit();
}
You are terminating the script prematurely.
simpleParser is being executed asynchronously. Therefore this bit console.log('Exit'); process.exit(); is being called before your simpleParser has finished.
We experienced this exact same behavior. The above responders are correct in that the console.log commands are not logging anything within the mailparser function because it is running asynchronously and the calling function is exiting without waiting on the mailparser to do its thing.
The simple solution for us was to just call the mailparser with await so the calling function waits on mailparser to complete before it continues.
So, instead of:
simpleParser(data.Body, (err, mail) => {console.log('message');});
Try this:
let mail = await simpleParser(data.Body);
if (mail != null) {console.log('message');};
For what it's worth, I think the asynchronous simpleParser function without the await should still be running through its internal code. It's just the logging messages won't be recorded as the calling function may have exited at the time.

Resources