Where am I supposed to catch this Promise MongoError?

Viewed 595

I upgraded my mongoose, so of course I started getting these:

DeprecationWarning: Mongoose: mpromise (mongoose's default promise library)
is deprecated, plug in your own promise library instead:
http://mongoosejs.com/docs/promises.html

so I added mongoose.Promise = global.Promise. All good. Except... now I get this guy:

(node:20760) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: exception: Index with name: stampRoundedToNearestHour_1 already exists with different options
(node:20760) [DEP0018] 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.

It's easy enough to fix the underlying error, but I have no clue where I'm supposed to be catching it so that future versions of Node won't suddenly crash if they encounter similar things. I've produced a minimal version of my code that produces the error. This is one javascript file:

var mongoose = require('mongoose')
mongoose.Promise = global.Promise

var TestSchema = mongoose.Schema({
  num: Number,
})

TestSchema.index({'num': 1}, { sparse: true })
TestSchema.index({'num': 1}, { sparse: false })
// The above line is deliberately designed to be problematic.
// My question isn't how to not get an error,
// it's that I don't know where to catch it when I do!

// If this line is commented out, there's no error
// but it doesn't return a promise, so I can't .then or .catch on it
var Test = mongoose.model('Test', TestSchema)

mongoose.connect(process.env.MONGOLAB_URI, {useMongoClient: true})
.then(function () {
  console.log("mongoose.connected successfully")
}).catch(function (err) {
  console.log("mongoose.connect catch", err)
})

As you can see, I tried both kinds of error handling on the mongoose.connect() function, but what is output when I run this is

mongoose.connected successfully
(node:26795) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): MongoError: exception: Index with name: num_1 already exists with different options
(node:26795) [DEP0018] 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.

I have tried adding .catch(...) to literally every other function here:

  • mongoose.Schema(...)
  • TestSchema.index({'num': 1}, { sparse: true })
  • mongoose.model('Test', TestSchema)
  • and even require('mongoose') (this felt dumb, but I tried it)

...and also to some other functions in my system that I was able to remove while keeping the code broken.

But in all of these cases TypeError: WHATEVER.catch is not a function.

Where am I supposed to be catching this MongoError? (Again, I know how to prevent it)

2 Answers

The reason you're getting this is due to duplicate indexes being defined.

You should only have one of these lines.

TestSchema.index({'num': 1}, { sparse: true })
TestSchema.index({'num': 1}, { sparse: false })

The Unhandled promise is actually coming from a rejection in node-mongodb-native related to createIndex. This is not exposed in mongoose for you to catch errors on.

The likely logical reasoning is simply that you should never have errors in your schema definition. This is something that could/should be easily caught during development and will not repeat itself later.

After looking around a bit more and finding this article, one possible answer to this question could be adding this line:

process.on('unhandledRejection', function(error) {
  // do something with this error
})

Doing this means that this warning goes away:

(node:26795) [DEP0018] 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.

But I don't actually know that this would keep the Node.js process from exiting.

Related