[CSHARP-3272] Don't throw non-specific Exceptions Created: 27/Nov/20  Updated: 27/Oct/23  Resolved: 04/Dec/20

Status: Closed
Project: C# Driver
Component/s: Error Handling
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major - P3
Reporter: Alex Bevilacqua Assignee: Robert Stam
Resolution: Works as Designed Votes: 6
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Case:

 Description   

Similar cases have been closed in the past (CSHARP-155, CSHARP-474, CSHARP-153) however the issue still persists.

For example:

[TestMethod]
public void ShouldRaiseBetterErrors()
{
    const string CONN = "mongodb://localhost:27017";
    var client = new MongoClient(MongoUrl.Create(CONN));
    var database = client.GetDatabase("test");
    database.DropCollection("foo");
    var collection = database.GetCollection<BsonDocument>("foo");
 
    var search = "Test\0Test";
    var regex = new BsonRegularExpression(string.Format(".*{0}.*", search), "i");
    var filter = Builders<BsonDocument>.Filter.Gt("_id", regex);
    try
    {
        var result = collection.Find(filter).FirstOrDefault();
    }
    catch (ArgumentException e) when (e.Message == "A CString cannot contain null bytes." && e.ParamName == "value")
    {
        throw new ApplicationException("You are trying to query with a string that contains a null character, this is not supported");
    }
}

In the above example, when a CStringUtf8Encoding detects a null byte an ArgumentException is raised.

As this exception can be raised as any part of a command, to capture context this specific exception would need to be caught and re-thrown.

A more appropriate method would be to ensure errors are all enumerated and error codes accessible from the exception instance such as:

public enum ErrorCodes
{
  //...
  InvalidCString = 10001
  //...
}
// ...
namespace MongoDB.Bson.IO
{
    internal static class CStringUtf8Encoding
    {
        public static int GetBytes(string value, byte[] bytes, int byteIndex, UTF8Encoding fallbackEncoding)
        {
            var charLength = value.Length;
            var initialByteIndex = byteIndex;
 
            for (var charIndex = 0; charIndex < charLength; charIndex++)
            {
                var c = (int)value[charIndex];
                if (c == 0)
                {
                    throw new MongoDriverException { Code = ErrorCodes.InvalidCString, Message = "A CString cannot contain null bytes.", ... });
                }
                // ...
            }
            // ...
        }
    }
}

This approach is similar to what the server does with error_codes.yml.

Note that a search of the mongodb/mongo-csharp-driver for "throw new ArgumentException" provides a number of similar examples.



 Comments   
Comment by Robert Stam [ 04/Dec/20 ]

While we agree that examining exception message strings to glean more detail about what happened is fragile (in part because error messages might be reworded) and while we agree that numeric error codes are not a bad idea in theory, we don't think we can change the driver to throw new types of exceptions. That would break any existing application that is catching the existing exceptions.

In this particular scenario it seems like the proper application design is to validate the user provided input *before* passing it to the driver rather than passing bad data to the driver and trying to decode the resulting exception.

Generated at Wed Feb 07 21:44:52 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.