mongoose: Handle cast error on find when objectId is invalid

Do you want to request a feature or report a bug? Bug

What is the current behavior? I’m trying to find an item by its _id, but when I try to handle the possible “error”, when the client sends an id that doesn’t exist and then return it as an user friendly error, it’s getting into the “catch” function and resulting in an Error 500 to the user with a very big error message.

I tried to find a method to handle it on google and even here, but I didn’t find anything.

If the current behavior is a bug, please provide the steps to reproduce.

ToDo.findById(todoId)
.then(result => {
    return httpResponse.success(res, "Data successfully fetched", result)
})
.catch(err => {
    // When the ID isn't valid, it shows up as an error
    return httpResponse.error(res, err, "Error while fetching the ToDo data on the database");
})

What is the expected behavior? I want to handle this kind of “error” that for me isn’t an error. It’s just an invalid item to search.

Please mention your node.js, mongoose and MongoDB version. Node: v7.4.0 Mongoose: 4.10.5 MongoDB: v3.4.4

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 6
  • Comments: 30 (2 by maintainers)

Most upvoted comments

This is expected behavior and your way of handling the error is mostly correct. I’d recommend instead doing:

.catch(err => {
    if (err.message instanceof mongoose.Error.CastError)
        return httpResponse.success(res, "Data was not found", null);

    return httpResponse.error(res, err, "Error while fetching the data on the database");
})

Checking for instanceof CastError is more robust because the error message may change.

If you don’t want to execute this check for every find operation you can use error handling middleware to transform the error into something that is appropriate for your application.

Yes, I can do that. I’m already doing something similar actually. But, I don’t know… For me, a better approach for those cases would be returning an empty user instead of throwing an error.

This is my currently approach:

ToDo.findOne({ _id: todoId, createdBy: userId })
.populate(['createdBy', 'updatedBy'])
.then(result => {
    if (!result) return httpResponse.wrong(res, statusCode.error.NOT_FOUND, `Data was not found`);
        
    return httpResponse.success(res, "Data successfully fetched", result)
})
.catch(err => {
    if (err.message.indexOf('Cast to ObjectId failed') !== -1)
        return httpResponse.success(res, "Data was not found", null);

    return httpResponse.error(res, err, "Error while fetching the data on the database");
})

@youssefsharief It’s this way:

if (err instanceof mongoose.CastError) {
  // Handle this error
}

Thanks for the explanation @vkarpov15.

Tricky to implement in the code ? In my opinion I don’t think that returning null for Model.findById(123) is strange, but you’re right it can be useful in some cases (especially in dev) to know exactly what’s the error.

But let’s say you have an API, if you don’t want your code to throw internal errors every time an API user use a wrong parameter (/song/:wrong_song_id), you would have to validate the parameters before every Model.find() or create a new static that handles that. It would be very useful to have such a basic thing already in mongoose.

Just a suggestion but maybe a property throwCastError: false (true by default) in the mongoose config could be an option ? That way the people who wants to handle the cast errors like a model not found could do so, In my case I would be able to enable this option in production. Being able to prevent an error in the error handling middleware would be a much powerful feature but I can understand it can be tricky to implement.

sorry for the late response. anyway, i think this is potentially backwards breaking but ill label it an enhancement for now, will wait for @vkarpov15 's thoughts