0
votes

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://[email protected]: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

2
What is the value of uri or uri()? Can you provide it's structure or some dummy data? - zero298
I did. see quote above beginning with "To prove the point..." - ekkis

2 Answers

1
votes

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")
}
0
votes

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.