-
Type: Bug
-
Resolution: Done
-
Priority: Major - P3
-
None
-
Affects Version/s: 2.10.2
-
Component/s: Error Handling, Serialization
-
None
-
Environment:MongoDB Server version: 4.2.3
Host: Windows 10 Enterprise 64bit
MongoDB.Driver: 2.10.2
The internal creation of an MongoWriteException will itself cause an exception.
An exception of this type "MongoWriteException.WriteError.Category == ServerErrorCategory.DuplicateKey" will include the violating key value, e.g. "abc", in the exception message.
'A write operation resulted in an error.
E11000 duplicate key error collection: test.data index: Id_1 dup key: { : "abc" }'
If the target collection has a collation set, e.g. collation.locale='sv', the value will have another encoding. The exception message will now show the key value "def" in this way "/13"
MongoWriteException (DuplicateKey detected): 'A write operation resulted in an error.
E11000 duplicate key error collection: test.data index: Id_1 dup key: { : "/13" }'
If the key value is a little bit longer, say "abcdefghijkl123456789" then some deserialization of the original exception will fail and produce:
Exception: 'Unable to translate bytes [85] at index 88 from specified code page to Unicode.'
The consequence is that we at his point have lost control in an application of what's happening with the database operation.
Here are some code to reproduce the issue:
using MongoDB.Bson; using MongoDB.Driver; using System; namespace DuplicateKeyException { class Program { private static readonly string connectionString = "mongodb://localhost:27017/"; private static readonly string databaseName = "test"; private static readonly string collectionName = "data"; static void Main(string[] args) { Console.WriteLine("--- Reproduce bug in MongoDb exception deserialization ---\n"); var client = new MongoClient($"{connectionString}{databaseName}"); var database = client.GetDatabase(databaseName); var collection = CreateCollection(database, collectionName); TryInsertDoc("abc", collection); TryInsertDoc("abc", collection); collection = CreateCollection(database, collectionName, "sv"); TryInsertDoc("def", collection); TryInsertDoc("def", collection); TryInsertDoc("abcdefghijkl123456789", collection); TryInsertDoc("abcdefghijkl123456789", collection); Console.ReadLine(); } private static void TryInsertDoc(string id, IMongoCollection<BsonDocument> coll) { var doc= new BsonDocument { { "Id", id } }; try { Console.WriteLine($"Try insert doc with Id: '{doc.GetValue("Id").AsString}'"); coll.InsertOne(doc); Console.WriteLine($"Inserted doc with Id: '{doc.GetValue("Id").AsString}'"); } catch (MongoWriteException writeEx) { if (writeEx != null && writeEx.WriteError.Category == ServerErrorCategory.DuplicateKey) { Console.WriteLine($"MongoWriteException (DuplicateKey detected): '{writeEx.Message}'"); } else { Console.WriteLine($"MongoWriteException: '{writeEx.Message}'"); } } catch (Exception e) { Console.WriteLine($"Exception: '{e.Message}'"); } finally { Console.WriteLine("---------------------"); } } private static IMongoCollection<BsonDocument> CreateCollection(IMongoDatabase database, string name, string collationLocale=null) { Console.Write($"Create collection '{name}' with unique index"); database.DropCollection(name); if(!string.IsNullOrEmpty(collationLocale)) { database.CreateCollection(name, new CreateCollectionOptions { Collation = new Collation("sv", strength: CollationStrength.Primary, numericOrdering: true) }); Console.Write($" and collation.locale='{collationLocale}'"); } var collection = database.GetCollection<BsonDocument>(name); var indexOptions = new CreateIndexOptions() { Unique = true, }; var indexKeys = Builders<BsonDocument>.IndexKeys.Ascending("Id"); var indexModel = new CreateIndexModel<BsonDocument>(indexKeys, indexOptions); collection.Indexes.CreateOneAsync(indexModel).Wait(); Console.WriteLine(); Console.WriteLine("---------------------"); return collection; } } }
The resulting output:
--- Reproduce bug in MongoDb exception deserialization --- Create collection 'data' with unique index --------------------- Try insert doc with Id: 'abc' Inserted doc with Id: 'abc' --------------------- Try insert doc with Id: 'abc' MongoWriteException (DuplicateKey detected): 'A write operation resulted in an error. E11000 duplicate key error collection: test.data index: Id_1 dup key: { : "abc" }' --------------------- Create collection 'data' with unique index and collation.locale='sv' --------------------- Try insert doc with Id: 'def' Inserted doc with Id: 'def' --------------------- Try insert doc with Id: 'def' MongoWriteException (DuplicateKey detected): 'A write operation resulted in an error. E11000 duplicate key error collection: test.data index: Id_1 dup key: { : "/13" }' --------------------- Try insert doc with Id: 'abcdefghijkl123456789' Inserted doc with Id: 'abcdefghijkl123456789' --------------------- Try insert doc with Id: 'abcdefghijkl123456789' Exception: 'Unable to translate bytes [85] at index 88 from specified code page to Unicode.' ---------------------
And the stack trace:
at System.Text.DecoderExceptionFallbackBuffer.Throw(Byte[] bytesUnknown, Int32 index) at System.Text.DecoderExceptionFallbackBuffer.Fallback(Byte[] bytesUnknown, Int32 index) at System.Text.Encoding.GetCharCountWithFallback(ReadOnlySpan`1 bytes, Int32 originalBytesLength, DecoderNLS decoder) at System.Text.Encoding.GetCharCountWithFallback(Byte* pBytesOriginal, Int32 originalByteCount, Int32 bytesConsumedSoFar) at System.Text.UTF8Encoding.GetCharCount(Byte* bytes, Int32 count) at System.String.CreateStringFromEncoding(Byte* bytes, Int32 byteLength, Encoding encoding) at System.Text.UTF8Encoding.GetString(Byte[] bytes, Int32 index, Int32 count) at MongoDB.Bson.IO.Utf8Helper.DecodeUtf8String(Byte[] bytes, Int32 index, Int32 count, UTF8Encoding encoding) at MongoDB.Bson.IO.ByteBufferStream.ReadString(UTF8Encoding encoding) at MongoDB.Bson.IO.BsonBinaryReader.ReadString() at MongoDB.Bson.Serialization.Serializers.BsonStringSerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) at MongoDB.Bson.Serialization.Serializers.BsonDocumentSerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) at MongoDB.Bson.Serialization.Serializers.BsonArraySerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) at MongoDB.Bson.Serialization.Serializers.BsonDocumentSerializer.DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.BsonValueSerializerBase`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context) at MongoDB.Driver.Core.WireProtocol.CommandUsingCommandMessageWireProtocol`1.ProcessResponse(ConnectionId connectionId, CommandMessage responseMessage) at MongoDB.Driver.Core.WireProtocol.CommandUsingCommandMessageWireProtocol`1.Execute(IConnection connection, CancellationToken cancellationToken) at MongoDB.Driver.Core.WireProtocol.CommandWireProtocol`1.Execute(IConnection connection, CancellationToken cancellationToken) at MongoDB.Driver.Core.Servers.Server.ServerChannel.ExecuteProtocol[TResult](IWireProtocol`1 protocol, ICoreSession session, CancellationToken cancellationToken) at MongoDB.Driver.Core.Servers.Server.ServerChannel.Command[TResult](ICoreSession session, ReadPreference readPreference, DatabaseNamespace databaseNamespace, BsonDocument command, IEnumerable`1 commandPayloads, IElementNameValidator commandValidator, BsonDocument additionalOptions, Action`1 postWriteAction, CommandResponseHandling responseHandling, IBsonSerializer`1 resultSerializer, MessageEncoderSettings messageEncoderSettings, CancellationToken cancellationToken) at MongoDB.Driver.Core.Operations.RetryableWriteCommandOperationBase.ExecuteAttempt(RetryableWriteContext context, Int32 attempt, Nullable`1 transactionNumber, CancellationToken cancellationToken) at MongoDB.Driver.Core.Operations.RetryableWriteOperationExecutor.Execute[TResult](IRetryableWriteOperation`1 operation, RetryableWriteContext context, CancellationToken cancellationToken) at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase`1.ExecuteBatch(RetryableWriteContext context, Batch batch, CancellationToken cancellationToken) at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase`1.ExecuteBatches(RetryableWriteContext context, CancellationToken cancellationToken) at MongoDB.Driver.Core.Operations.BulkUnmixedWriteOperationBase`1.Execute(RetryableWriteContext context, CancellationToken cancellationToken) at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.ExecuteBatch(RetryableWriteContext context, Batch batch, CancellationToken cancellationToken) at MongoDB.Driver.Core.Operations.BulkMixedWriteOperation.Execute(IWriteBinding binding, CancellationToken cancellationToken) at MongoDB.Driver.OperationExecutor.ExecuteWriteOperation[TResult](IWriteBinding binding, IWriteOperation`1 operation, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionImpl`1.ExecuteWriteOperation[TResult](IClientSessionHandle session, IWriteOperation`1 operation, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IClientSessionHandle session, IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionImpl`1.<>c__DisplayClass23_0.<BulkWrite>b__0(IClientSessionHandle session) at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSession[TResult](Func`2 func, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionImpl`1.BulkWrite(IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken) at MongoDB.Driver.MongoCollectionBase`1.<>c__DisplayClass64_0.<InsertOne>b__0(IEnumerable`1 requests, BulkWriteOptions bulkWriteOptions) at MongoDB.Driver.MongoCollectionBase`1.InsertOne(TDocument document, InsertOneOptions options, Action`2 bulkWrite) at MongoDB.Driver.MongoCollectionBase`1.InsertOne(TDocument document, InsertOneOptions options, CancellationToken cancellationToken) at DuplicateKeyException.Program.TryInsertDoc(String id, IMongoCollection`1 coll) in C:\Src\Project\DuplicateKeyException\Program.cs:line 41