This is an automated email from the ASF dual-hosted git repository.

Cole-Greer pushed a commit to branch GLVBehaviouralAlignment
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 4846117c33d7873e6b82c1e4f5c823aaaf651d0d
Author: Cole Greer <[email protected]>
AuthorDate: Tue Jun 2 12:37:55 2026 -0700

    Wrap malformed-response deserialization errors in gremlin-dotnet
    
    - Add ResponseDeserializationException and wrap response-deserialization
      failures so a malformed response yields a single consistent exception type
      instead of a non-deterministic IOException/KeyNotFoundException
      (tinkerpop-9t5).
    - Leave transport-level HttpIOException (premature connection close) 
unwrapped
      so the partial-content-close path keeps its transport-error semantics.
    - Update behavioral test assertions.
---
 .../src/Gremlin.Net/Driver/Connection.cs           |  8 +++++
 .../Exceptions/ResponseDeserializationException.cs | 42 ++++++++++++++++++++++
 .../Driver/ClientBehaviorIntegrationTests.cs       | 14 +++-----
 3 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs 
b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
index e5c94611d4..89419592f7 100644
--- a/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
+++ b/gremlin-dotnet/src/Gremlin.Net/Driver/Connection.cs
@@ -30,6 +30,7 @@ using System.Net.Http.Headers;
 using System.Threading;
 using System.Threading.Channels;
 using System.Threading.Tasks;
+using Gremlin.Net.Driver.Exceptions;
 using Gremlin.Net.Driver.Messages;
 using Gremlin.Net.Process;
 using Gremlin.Net.Process.Traversal;
@@ -264,6 +265,13 @@ namespace Gremlin.Net.Driver
                         }
                         channel.Writer.Complete();
                     }
+                    catch (Exception ex) when (ex is not ResponseException
+                                                    and not 
OperationCanceledException
+                                                    and not HttpIOException)
+                    {
+                        channel.Writer.Complete(
+                            new ResponseDeserializationException(ex));
+                    }
                     catch (Exception ex)
                     {
                         channel.Writer.Complete(ex);
diff --git 
a/gremlin-dotnet/src/Gremlin.Net/Driver/Exceptions/ResponseDeserializationException.cs
 
b/gremlin-dotnet/src/Gremlin.Net/Driver/Exceptions/ResponseDeserializationException.cs
new file mode 100644
index 0000000000..01912507c6
--- /dev/null
+++ 
b/gremlin-dotnet/src/Gremlin.Net/Driver/Exceptions/ResponseDeserializationException.cs
@@ -0,0 +1,42 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+
+namespace Gremlin.Net.Driver.Exceptions
+{
+    /// <summary>
+    ///     The exception that is thrown when the driver fails to deserialize 
a response received from Gremlin Server.
+    /// </summary>
+    public class ResponseDeserializationException : Exception
+    {
+        /// <summary>
+        ///     Initializes a new instance of the <see 
cref="ResponseDeserializationException" /> class.
+        /// </summary>
+        /// <param name="innerException">The exception that caused the 
deserialization failure.</param>
+        public ResponseDeserializationException(Exception innerException)
+            : base("Failed to deserialize the response received from Gremlin 
Server.", innerException)
+        {
+        }
+    }
+}
diff --git 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ClientBehaviorIntegrationTests.cs
 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ClientBehaviorIntegrationTests.cs
index 03977423b2..cb346adb20 100644
--- 
a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ClientBehaviorIntegrationTests.cs
+++ 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Driver/ClientBehaviorIntegrationTests.cs
@@ -173,17 +173,12 @@ namespace Gremlin.Net.IntegrationTest.Driver
         {
             SkipIfServerUnavailable();
 
-            // NOTE: the driver surfaces a low-level exception (no 
Gremlin-aware wrapping,).
-            // The exact type is non-deterministic for malformed bytes: either 
an IOException
-            // at the stream layer or a KeyNotFoundException from the 
GraphBinary deserializer,
-            // depending on how the chunk is read.
-            var ex = await Assert.ThrowsAnyAsync<Exception>(async () =>
+            var ex = await 
Assert.ThrowsAsync<ResponseDeserializationException>(async () =>
             {
                 var resultSet = await 
_client!.SubmitAsync<dynamic>(SocketServerConstants.GremlinMalformedResponse);
                 await resultSet.ToListAsync();
             });
-            Assert.True(ex is System.IO.IOException or KeyNotFoundException,
-                $"Unexpected exception type: {ex.GetType().FullName}");
+            Assert.NotNull(ex.InnerException);
 
             // Recovery
             var resultSet = await 
_client!.SubmitAsync<dynamic>(SocketServerConstants.GremlinSingleVertex);
@@ -196,12 +191,13 @@ namespace Gremlin.Net.IntegrationTest.Driver
         {
             SkipIfServerUnavailable();
 
-            var ex = await Assert.ThrowsAsync<System.IO.IOException>(async () 
=>
+            var ex = await 
Assert.ThrowsAsync<ResponseDeserializationException>(async () =>
             {
                 var resultSet = await 
_client!.SubmitAsync<dynamic>(SocketServerConstants.GremlinEmptyBody);
                 await resultSet.ToListAsync();
             });
-            Assert.Contains("Unexpected end of stream", ex.Message);
+            Assert.IsType<System.IO.IOException>(ex.InnerException);
+            Assert.Contains("Unexpected end of stream", 
ex.InnerException!.Message);
 
             // Recovery
             var resultSet = await 
_client!.SubmitAsync<dynamic>(SocketServerConstants.GremlinSingleVertex);

Reply via email to