.Net 2.7.x NullReference encountered on GetDocumentFromReplicaAsync<T> and GetFromReplicaAsync<T> when ssl is enabled

In working to update our 2.7.x client to use ssl connections to the cluster, we encountered a null reference when calling GetDocumentFromReplicaAsync<T> and GetFromReplicaAsync<T>.

Exception occurs here in library code: couchbase-net-client/CallbackFactory.cs at 2.7.17 · couchbase/couchbase-net-client · GitHub - the link is to 2.7.17 version we’re using, but the issue still exists on the latest 2.7.24 version.

Seems like the EndPoint is not mapped in SslConnection : couchbase-net-client/SslConnection.cs at 22628a63c2323cd9affdba58b227371e373798a6 · couchbase/couchbase-net-client · GitHub, while it is mapped in MultiplexingConnection : couchbase-net-client/MultiplexingConnection.cs at 22628a63c2323cd9affdba58b227371e373798a6 · couchbase/couchbase-net-client · GitHub

The only difference in our implementation is setting UseSsl = true on the bucket definition. Is this something we can address in our configuration? Seems like a defect with the client.

@brihulse -

Can you provide a code snippet of the configuration?

-Jeff

Here’s how we configure, initialize and access the cluster/buckets. Let me know if you need any more details.

public class CouchbaseBucketFactory : ICouchbaseBucketFactory
    {

        private static readonly Dictionary<CouchbaseBucketType, string> BucketMap = new Dictionary<CouchbaseBucketType, string>()
        {
            { CouchbaseBucketType.Cache, "cache" },
            { CouchbaseBucketType.Storage, "storage" },
        };

        private static readonly ConcurrentDictionary<CouchbaseBucketType, Lazy<IBucket>> Buckets = new ConcurrentDictionary<CouchbaseBucketType, Lazy<IBucket>>();

        public CouchbaseBucketFactory(ICouchbaseClientDefinitionProvider definitionProvider, IServerResolver serverResolver)
        {
            var definition = new CouchbaseClientDefinition
            {
                Servers = serverResolver.GetServers().ToList(),
                Buckets = definitionProvider.GetBuckets().Select(GetBucketDefinition).ToList(),
                ForceSaslPlain = definitionProvider.GetForceSaslPlain()
            };
            var clusterConfiguration = new ClientConfiguration(definition);

            var serializationSettings = new JsonSerializerSettings()
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                TypeNameHandling = TypeNameHandling.All
            };

            clusterConfiguration.Transcoder = () => new DefaultTranscoder(new DefaultConverter(), new DefaultSerializer(serializationSettings, serializationSettings));
            clusterConfiguration.Serializer = () => new DefaultSerializer(serializationSettings, serializationSettings);

            ClusterHelper.Initialize(clusterConfiguration);
        }

        private static BucketDefinition GetBucketDefinition(BucketConfigData bucket)
        {
            var connectionPool = new ConnectionPoolDefinition
            {
                MaxSize = bucket.ConnectionPool.MaxSize,
                MinSize = bucket.ConnectionPool.MinSize,
            };
            if (bucket.ConnectionPool.WaitTimeout.HasValue)
            {
                connectionPool.WaitTimeout = bucket.ConnectionPool.WaitTimeout.Value;
            }
            if (bucket.ConnectionPool.ShutdownTimeout.HasValue)
            {
                connectionPool.ShutdownTimeout = bucket.ConnectionPool.ShutdownTimeout.Value;
            }

            return new BucketDefinition
            {
                Name = bucket.Name,
                Password = bucket.Password,
                UseSsl = bucket.UseSsl,
                ConnectionPool = connectionPool
            };
        }

        public IBucket GetBucket(CouchbaseBucketType bucketType)
        {
            return Buckets.GetOrAdd(bucketType, PrivateGetBucket).Value;
        }

        private static Lazy<IBucket> PrivateGetBucket(CouchbaseBucketType bucketType)
        {
            var bucketName = BucketMap[bucketType];
            return new Lazy<IBucket>(() => ClusterHelper.Get().OpenBucket(bucketName), LazyThreadSafetyMode.ExecutionAndPublication);
        }
    }

@jmorris One important note that we found with additional testing today. We only see this null reference error when attempting to get a document from replica that does not exist.

I went back through and reviewed the documentation and the example here is showing it goes to replica on ResponseStatus.KeyNotFound status. Is this example misleading or would we see a ResponseStatus.KeyNotFound if the active node is unavailable?

@brihulse -

Thanks for the update. Do you have a stacktrace of the exception you can post?

Jeff

```
System.NullReferenceException: Object reference not set to an instance of an object.
    at Couchbase.Core.Buckets.CallbackFactory.CreateOperationContext(SocketAsyncState state, Nullable`1 serverDuration, String bucketName)
   at Couchbase.Core.Buckets.CallbackFactory.<>c__DisplayClass7_0`1.<<CompletedFuncForRetry>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Couchbase.Core.Server.SendAsync[T](IOperation`1 operation)
   at Couchbase.Core.Buckets.RequestExecuterBase.ReadFromReplicaAsync[T](ReplicaRead`1 operation)
   at Couchbase.CouchbaseBucket.GetDocumentFromReplicaAsync[T](String id, TimeSpan timeout)
   at Couchbase.CouchbaseBucket.GetDocumentFromReplicaAsync[T](String id, TimeSpan timeout)
```

@brihulse -

I created a ticket and patch for a fix based on what I see here. Feel free to create an account on review.couchbase.com and try it out.

Thanks,
Jeff

That’s great thanks! We’ve given it a shot and it works in our tests. Any idea on the timeline of when this would be officially released?

@brihulse

Good to hear, should be available the first week of June in v2.7.26

Jeff