I've got this code below that fetches once from firebase on nodejs. I'm purposely throwing an error and attempting to catch it, however, the error isn't being handled and my server keeps crashing and my catch statement isn't being executed.
FIREBASE WARNING: Exception was thrown by user callback. Error:
Article is not found
var ref = fdb.ref("Emojis");
ref.once("value", function (data) {
// do some stuff once
throw Error('Article is not found');
console.log(data.val());
}).catch(error => {
console.log('an error happenned')
});
I also tried this code and the error is still not handled:
ref.once("value", function (snapshot) {
throw Error('Article is not found');
console.log(snapshot.val());
}, function (errorObject) {
console.log("The read failed: " + errorObject.code);
});
Related
I'm trying to handle an exception thrown in an fs.createReadStream, and I use a Promise for that, but the error terminates the API, despite the .catch.
What am I doing wrong ?
Here is my test code :
fcts = require('./functions.js');
app.get('/test', function(req, res){
console.log("OK TEST")
fcts.test(req, res, '/data/file')
.then(result => console.log("OK"))
.catch(err => console.log("NO"))
})
module.exports = {
test: function (request, response, fichier){
return new Promise((resolve, reject) => {
var flux = fs.createReadStream(fichier)
.on('error', function(err){
console.log("no")
reject("reject")
})
.on('close', function(){
console.log("end")
resolve("ok")
})
.pipe(unzip.Parse())
.on('entry', function (entry) {
throw("uh")
});
console.log("end end")
})
}
}
Here are my logs:
...
OK TEST
end end
.../functions.js:1493
throw("uh")
^
uh
I am using node 8.16.0 and express-js
Thanks !
It will work if you reject instead of throwing :
.on('entry', function (entry) {
reject(new Error('uh'));
});
Throwing in a callback used by an async function inside a Promise definition function will not work, because the context in wich it have been thrown is not the promise one, but the one of the createReadStream that don't seems to trigger the error event for an exception thrown in a callback you defined with on.
In fact, in your case, the error that is thrown is an UncaughtException, because the context in wich the error occurs doesn't catch it. Since it is in an asynchronous context, it's the node.js context that notice the error.
Why ? Maybe because the error event in only triggered for stream errors, not for callback executions failures.
When running your script in nodejs, you should use the flag --trace-uncaught nodejs --trace-uncaught ./myfile.js. it will prompt you more infos on uncaught exceptions when it occurs.
the answer to this question: How to get node to exit when mongo connect fails contains async/wait code for a connection
however, my code (running on node v11.5.0 and mongodb v3.1.13) is failing to catch:
(async function() {
let db;
try {
db = await MongoClient.connect(uri, { useNewUrlParser: true });
console.log("RETURN", db);
} catch (err) {
console.log('EXITING');
process.exit(1);
}
}());
to prove the point I intentionally give a uri without credentials:
mongodb://undefined#cluster0-shard-00-00-z4j9e.azure.mongodb.net:27017,cluster0-shard-00-01-z4j9e.azure.mongodb.net:27017,cluster0-shard-00-02-z4j9e.azure.mongodb.net:27017/test?ssl=true&replicaSet=Cluster0-shard-0&authSource=admin&retryWrites=true
and what I get is output like this:
/Users/ekkis/dev/mongo/node_modules/mongodb/lib/topologies/replset.js:346
throw err;
^
MongoError: password must be a string
at passwordDigest (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/auth/scram.js:63:43)
at ScramSHA1.ScramSHA.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/auth/scram.js:175:25)
at authenticate (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:232:17)
at authenticateLiveConnections (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:819:7)
at /Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:864:5
at waitForLogout (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:855:34)
at Pool.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/connection/pool.js:862:3)
at Server.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/topologies/server.js:931:20)
at auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/topologies/replset.js:1474:19)
at ReplSet.auth (/Users/ekkis/dev/mongo/node_modules/mongodb-core/lib/topologies/replset.js:1492:5)
so if the error had been caught, the console should have displayed the word 'EXITING', but does not. additionally, I contend an exception was thrown because otherwise the returned value would have been printed, which it was not
how can this be? what do I need to do to get it to work?
* Appendix I *
In fact, the promises version of this exhibits the same odd behaviour, it doesn't catch:
MongoClient
.connect(uri, { useNewUrlParser: true })
.then(dbc => {
console.log('SUCCESS');
})
.catch(err => {
console.log('EXITING');
process.exit(1);
});
and yes, I tested the callback version, which also suffers the same malady. Incidentally, passing an empty string for the uri works well. I don't get it
* Appendix II *
In fact, the problem seems to be particular to the credentials passed i.e. if I pass:
mongodb://x:y#cluster0-shard-[...]
I catch a "MongoError: authentication fail" as expected. passing:
mongodb://#cluster0-shard-[...]
interestingly returns a connection but credentials missing a ":" fail in this odd way, so:
mongodb://ekkis#cluster0-shard-[...]
fails to catch
Looks to me like it's a bug with however MongoClient is setting up its connections. You won't be able to use try & catch to handle asynchronously thrown errors within MongoClient code.
const {MongoClient} = require("mongodb");
process.on("uncaughtException", (err) => {
console.log("process err", err);
process.exit(1)
})
async function run () {
let db;
try {
// connection url will throw because password isn't provided
db = await MongoClient.connect("mongodb://myUsername:#localhost", { useNewUrlParser: true });
} catch (err) {
console.log('Exiting from thrown error', err);
process.exit(1);
}
}
run();
Here's a simplified example of what's happening -- the error will end up "uncaught" and caught by the uncaughtException handler
process.on("uncaughtException", (err) => console.log("uncaught", err));
try {
setTimeout(() => {
throw new Error("asynchronously thrown error");
})
} catch (err) {
console.log("Error will not be caught here")
}
When I was using mongo version 3.6.1, it was not an issue and i was able to handle the thrown exception using catch. But after a few days on another project this type of error occurred and was showing as the error thrown from
%project_folder%/node_modules/mongodb/lib/utils.js:668
(Don't mind about the slash in the path string.)
The mongodb version this time is 3.6.3. Upon checking the code in that file at the mentioned line I found the below piece of code. where the caught error is again being thrown.
fn(function(err, res) {
if (err != null) {
try {
callback(err);
} catch (error) {
return process.nextTick(() => {
throw error;
});
}
return;
}
callback(err, res);
});
I changed the throw error to console.error(error) and the problem got resolved. But still you need to be caught somewhere in our code where connect function is called.
I think this is because the above piece of code is checking for the presence of error and passing it to the callback function and then again throwing the same error again. I suppose it is the MongoDB driver developer community's responsibility to resolve this issue.
Im trying to download a file from S3 which doesn't exist on S3. I expect a error in this scenario and im also getting that error from aws-sdk i.e.
**/vagrant/node_modules/aws-sdk/lib/request.js:31
throw err;
^
NoSuchKey: The specified key does not exist.**
But the issue is, im not able to catch this error. If you check the code below, my listener request.on gets called and when i call reject in that the promise doesn't return from method downloadFontInfoFileFromS3 with reject.
Is there any way i can catch the error and gracefully reject the promise from downloadFontInfoFileFromS3 function?
downloadFontInfoFileFromS3(fileKey) {
return new Promise((resolve, reject) => {
const sThree = new awsSDK.S3();
const options = {
Bucket: awsConf.bucket,
Key: fileKey,
};
const downloadFilePath = SOME_PATH
const file = fs.createWriteStream(downloadFilePath);
const request = sThree.getObject(options);
const download = request
.createReadStream().pipe(file);
// called when error in aws-sdk
request.on('error', (error) => {
logger.error('Failed to download file from S3:', error.message);
reject(error);
});
download.on('error', (error) => {
reject(error);
});
download.on('finish', () => {
resolve(downloadFilePath);
});
// the synchronous code that we want to catch thrown errors on
});
}
I ran into this issue as well. Turns out I wasn't setting the error handler in the correct place.
Currently, you have:
// INCORRECT. Won't work
const download = request.createReadStream().pipe(file);
download.on('error', (error) => {
reject(error);
});
But you actually need to set the error handler on the stream, before you begin piping. Like this:
// Correct!
const download = request.createReadStream(); // notice the `.pipe()` has been removed
download.on('error', (error) => {
reject(error);
});
// now you can begin piping to the file
requestStream.pipe(file);
If you try setting the event handler after the pipe has begun, the error will "bypass" any try/catch or Promise .catch handlers you specify. Quite frustrating!
Check out this GitHub issue for another example.
const data = s3.getObject({ Bucket: process.env.AWS_BUCKET_NAME, Key: url }).createReadStream();
data.on("error", (err) => {
if (err)
return next(customError("Invalid Url", 400));
});
data.pipe(res);
Right Because Error is occourd when data in pipe.
Using Node.js + Express (4) + Mongoose (using promises rather than callbacks), I can’t sort out how to tidy up my error handling.
What I've got (rather simplified) is:
app.get('/xxx/:id', function(request, response) {
Xxx.findById(request.params.id).exec()
.then(function(xxx) {
if (xxx == null) throw Error('Xxx '+request.params.id+' not found');
response.send('Found xxx '+request.params.id);
})
.then(null, function(error) { // promise rejected
switch (error.name) {
case 'Error':
response.status(404).send(error.message); // xxx not found
break;
case 'CastError':
response.status(404).send('Invalid id '+request.params.id);
break;
default:
response.status(500).send(error.message);
break;
}
});
});
Here, in the switch in the ‘promise rejected’ section, the Error is the error I threw myself for a potentially valid id which is not found, the CastError is Cast to ObjectId failed thrown by Mongoose for an invalid id, and the 500 error can for instance be triggered by mistyping throw Error() as throw Err() (causing a ReferenceError: Err is not defined).
But like this, every one of my routes has this great big clumsy switch to handle the different errors.
How can I centralise the error handling? Can the switch be tucked away into some middleware somehow?
(I did hope I could just re-throw using throw error; within the 'promise rejected' block, but I haven’t been able to make it work).
I would create middleware to handle errors. Using next() for 404s. and next(err) for other errors.
app.get('/xxx/:id', function(req, res, next) {
Xxx.findById(req.params.id).exec()
.then(function(xxx) {
if (xxx == null) return next(); // Not found
return res.send('Found xxx '+request.params.id);
})
.then(null, function(err) {
return next(err);
});
});
404 handler
app.use(function(req, res) {
return res.send('404');
});
Error handler
app.use(function(err, req, res) {
switch (err.name) {
case 'CastError':
res.status(400); // Bad Request
return res.send('400');
default:
res.status(500); // Internal server error
return res.send('500');
}
});
You can improve upon this more by sending a json response like:
return res.json({
status: 'OK',
result: someResult
});
or
return res.json({
status: 'error',
message: err
});
In my application i want to create own module to capture my application error using uncaughtException.If i create uncaughtException in same module means its capturing errors but if i create that uncaughtException in separate module.Then call that module means its not capturing erros.Can anyone help me to fix this issue.
module1.js
var errorModule=require('./module2');
var err = new Error('Something went terribly wrong');
errorModule.captureError(err);
module2.js
module.exports.captureError=function(err){
process.on('uncaughtException', function(err) {
console.log(err);
});
}
Try this:
// module1.js
var errorModule=require('./module2');
errorModule.captureErrors();
throw Error('Something went terribly wrong');
// module2.js
module.exports.captureErrors = function() {
process.on('uncaughtException', function(err) {
console.log('an error occurred', err);
});
};
A few things to notice:
process.on('uncaughtException', ...) installs an event handler to catch uncaught exceptions; your code tries to pass an error to it, but that seems to defeat what you're writing ('to capture my application error using uncaughtException');
Uncaught exceptions are errors which are thrown (throw Error(...));
If you want the code in your module1 to work, module2 needs to look like this:
module.exports.captureError = function(err) {
console.log(err);
};
But that has nothing to do with uncaughtException.