Node.js UnhandledPromiseRejectionWarning even after catching it

I am using Node 7.2.1 with the new async / await function. I also use Native ES6 Promises with a mongoose-like -

const mongoose = require('mongoose'); mongoose.Promise = global.Promise; 

My code stream is like this:

 async function getFollowers(){ try { const followers = await User.getFollowersFromMongo(req.params.userId); res.send(followers); } catch (err) { winston.error('Printing Error = ', err); res.status(400).send({success: false, error: err}); } } UserSchema.statics.getFollowersFromMongo = async(userId) => { try { let aggregateQuery = []; //some syntactical error in mongo query to produce exception const followers = await User.aggregate(aggregateQuery); return followers.map(follower => follower.followerData); } catch (err) { return Promise.reject(err); } }; 

This code is working absolutely fine. A problem occurs when some error occurs. Therefore, I intentionally changed my request to mongoose so that MongoDB throws an error.

Now MongoDB, as expected, generates an error that gets into my code perfectly and returns to the client with error code 400.

The problem is that even if the error (intentional) was caught by me, Node.js still gives me this warning -

 error: Printing Error = MongoError: path option to $unwind stage should be prefixed with a '$': followerData at Function.MongoError.create (/home/node_modules/mongodb-core/lib/error.js:31:11) at /home/node_modules/mongodb-core/lib/connection/pool.js:483:72 at authenticateStragglers (/home/node_modules/mongodb-core/lib/connection/pool.js:429:16) at Connection.messageHandler (/home/node_modules/mongodb-core/lib/connection/pool.js:463:5) at Socket.<anonymous> (/home/node_modules/mongodb-core/lib/connection/connection.js:317:22) at emitOne (events.js:96:13) at Socket.emit (events.js:188:7) at readableAddChunk (_stream_readable.js:176:18) at Socket.Readable.push (_stream_readable.js:134:10) at TCP.onread (net.js:551:20) GET /user/385/followers 400 39.868 ms - 263 (node:10158) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: path option to $unwind stage should be prefixed with a '$': followerData (node:10158) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code. 

As you can see, my request returned status 400, and my error log was also printed from the catch block of the source code, but Node.js still says that the error message is not being processed.

Why does he talk about this even after the error has been caught?

Update - Thanks to @dvlsg and @Bergi, the bug was fixed in version 4.7.5

+6
source share
1 answer

Definitely, there seems to be something strange about how mongoose aggregates with async / await. This seems to be a mistake. If so, it must be reported to the mongoose.

Fortunately, there is easy work around:

 const followers = await User.aggregate(aggregateQuery).exec(); 

Adding an explicit .exec() allows me to catch a common pipeline error as expected.


I think the main problem with the confusion is that there is an extra floating around Promise that is rejected and not processed. Because technically you are correctly handling the expected deviation. Otherwise, you will not see that Printing error = ... logged.

Here, what I believe is happening -

  • You await User.aggregate()
  • Aggregate#then() is called via await , working with thenables (I think)
  • Aggregate#exec() is called inside Aggregate#then()
  • The new Promise inside Aggregate#exec() is created and will be rejected .
    • I believe this is a raw Promise .
  • Since the callback is provided by Aggregate#exec() from Aggregate#then() , an Error inside Aggregate#exec() will be provided for the callback
  • Inside the callback in Aggregate#then() new created Promise rejected
    • I believe that this Promise handled as expected, as it is returning from Aggregate#then()

I think I can confirm my suspicions by commenting on this line in the definition of mongoose Aggregate . This will prevent the raw deviation handler from getting into. Not that I propose doing this, by the way. This is just additional evidence, not a solution, because now I just don't have the deployed Promise floating around.


Here is a minimal way to reproduce a fuzzy deviation in a self-contained bit of code that should be run using node --harmony-async-await (tested on node v7.2.1 )

 const mongoose = require('mongoose'); mongoose.Promise = global.Promise; mongoose.connect('mongodb://localhost/temp'); const userSchema = new mongoose.Schema({ name: 'string' }); const User = mongoose.model('User', userSchema); async function run() { try { await User.aggregate([]); } catch (err) { console.log('caught expected error:', err); } } run(); 
+2
source

Source: https://habr.com/ru/post/1013354/


All Articles