Write errors on ordered bulk command results in GenericDriverException

22 views
Skip to first unread message

Jean-Baptiste Giraudeau

unread,
Jan 18, 2017, 12:35:54 PM1/18/17
to ReactiveMongo - http://reactivemongo.org
Hello,

While doing ordered bulk inserts I noticed that an error on a individual document get lost into a GenericDriverException.
I'd rather have a more structured LastError. (because I need to recover from duplicate key errors)

The reason of the behavior is that in reactivemongo.api.collections.GenericCollection.Mongo26WriteCommand#send we have:

       case Some(wr) if (wr.inError || (wr.hasErrors && ordered)) => {
          Future.failed(WriteResult.lastError(wr).
            getOrElse[Exception](GenericDriverException(
              s"write failure: $wr"
            )))
        }

and in reactivemongo.api.commands.WriteResult#lastError
:

  def lastError(result: WriteResult): Option[LastError] = result match {
    case error @ LastError(_, _, _, _, _, _, _, _, _, _, _, _, _, _) => Some(error)
    case _ if (result.ok) => None
    case _ => Some(LastError(
      false, // ok
      result.errmsg,


Eg, if mongo (tested with 3.2) fail to insert a document due to a duplicate key, it will return an response like:
{
  ok: BSONInteger(1),
  n: BSONInteger(0),
  writeErrors: [
    0: {
      index: BSONInteger(0),
      code: BSONInteger(11000),
      errmsg: "E11000 duplicate key error collection: test.events index: _id_ dup key: { : { key: ObjectId('56c6dc1eff2e140920771ee5'), seq: 12 } }"
    }
  ]
}


Has we can see, the corresponding write result will be "ok" despite writeErrors being non-empty. Hence we fall in the getOrElse clause resulting in errors being mangled into a GenericDriverException.

I guess one way to improve the situation is to change the implementation of
WriteResult#lastError into something more like

  def lastError(result: WriteResult): Option[LastError] = result match {
    case error @ LastError(_, _, _, _, _, _, _, _, _, _, _, _, _, _) => Some(error)

    case _
if (result.inError || result.hasErrors) => Some(LastError(
      false, // ok
      result.errmsg,
      ...
    case _ => None

WDYT?

Best regards,

Jb

Cédric Chantepie

unread,
Jan 18, 2017, 6:08:24 PM1/18/17
to ReactiveMongo - http://reactivemongo.org
PR welcome. Nothing planned about for now.
Reply all
Reply to author
Forward
0 new messages