From d49d5d36dbe2152b0b2dd14ed0ffedf6b9db1d49 Mon Sep 17 00:00:00 2001 From: William Chong Date: Mon, 13 Apr 2026 11:09:42 +0000 Subject: [PATCH] fix: prevent NRE on transport level gRPC errors --- src/KurrentDB.Client/Core/Exceptions/AccessDeniedException.cs | 3 ++- .../Exceptions/AppendTransactionMaxSizeExceededException.cs | 3 ++- src/KurrentDB.Client/Core/Exceptions/NotLeaderException.cs | 3 ++- .../Core/Exceptions/StreamTombstonedException.cs | 3 ++- .../Core/Exceptions/WrongExpectedVersionException.cs | 3 ++- src/KurrentDB.Client/Streams/KurrentDBClient.MultiAppend.cs | 3 +-- .../Streams/MaximumAppendSizeExceededException.cs | 3 ++- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/KurrentDB.Client/Core/Exceptions/AccessDeniedException.cs b/src/KurrentDB.Client/Core/Exceptions/AccessDeniedException.cs index c2a34eb36..91dfb2bdb 100644 --- a/src/KurrentDB.Client/Core/Exceptions/AccessDeniedException.cs +++ b/src/KurrentDB.Client/Core/Exceptions/AccessDeniedException.cs @@ -19,7 +19,8 @@ public AccessDeniedException() : base("Access denied.") { } - public static AccessDeniedException FromRpcException(RpcException ex) => FromRpcStatus(ex.GetRpcStatus()!); + public static AccessDeniedException FromRpcException(RpcException ex) => + FromRpcStatus(ex.GetRpcStatus() ?? throw ex); public static AccessDeniedException FromRpcStatus(Google.Rpc.Status ex) { return new(ex.Message, ex.ToRpcException()); diff --git a/src/KurrentDB.Client/Core/Exceptions/AppendTransactionMaxSizeExceededException.cs b/src/KurrentDB.Client/Core/Exceptions/AppendTransactionMaxSizeExceededException.cs index 1481b23c5..ddb73428b 100644 --- a/src/KurrentDB.Client/Core/Exceptions/AppendTransactionMaxSizeExceededException.cs +++ b/src/KurrentDB.Client/Core/Exceptions/AppendTransactionMaxSizeExceededException.cs @@ -21,7 +21,8 @@ public class AppendTransactionMaxSizeExceededException(int size, int maxSize, Ex /// public int MaxSize { get; } = maxSize; - public static AppendTransactionMaxSizeExceededException FromRpcException(RpcException ex) => FromRpcStatus(ex.GetRpcStatus()!); + public static AppendTransactionMaxSizeExceededException FromRpcException(RpcException ex) => + FromRpcStatus(ex.GetRpcStatus() ?? throw ex); public static AppendTransactionMaxSizeExceededException FromRpcStatus(Google.Rpc.Status ex) { var details = ex.GetDetail(); diff --git a/src/KurrentDB.Client/Core/Exceptions/NotLeaderException.cs b/src/KurrentDB.Client/Core/Exceptions/NotLeaderException.cs index bcd853f6b..c5fde5883 100644 --- a/src/KurrentDB.Client/Core/Exceptions/NotLeaderException.cs +++ b/src/KurrentDB.Client/Core/Exceptions/NotLeaderException.cs @@ -24,7 +24,8 @@ public NotLeaderException(string host, int port, Exception? exception = null) : LeaderEndpoint = new DnsEndPoint(host, port); } - public static NotLeaderException FromRpcException(RpcException ex) => FromRpcStatus(ex.GetRpcStatus()!); + public static NotLeaderException FromRpcException(RpcException ex) => + FromRpcStatus(ex.GetRpcStatus() ?? throw ex); public static NotLeaderException FromRpcStatus(Google.Rpc.Status ex) { var details = ex.GetDetail(); diff --git a/src/KurrentDB.Client/Core/Exceptions/StreamTombstonedException.cs b/src/KurrentDB.Client/Core/Exceptions/StreamTombstonedException.cs index 6c9ad341a..dfa0c4d28 100644 --- a/src/KurrentDB.Client/Core/Exceptions/StreamTombstonedException.cs +++ b/src/KurrentDB.Client/Core/Exceptions/StreamTombstonedException.cs @@ -19,7 +19,8 @@ public StreamTombstonedException(string stream, Exception? exception = null) Stream = stream; } - public static StreamTombstonedException FromRpcException(RpcException ex) => FromRpcStatus(ex.GetRpcStatus()!); + public static StreamTombstonedException FromRpcException(RpcException ex) => + FromRpcStatus(ex.GetRpcStatus() ?? throw ex); public static StreamTombstonedException FromRpcStatus(Google.Rpc.Status ex) { var details = ex.GetDetail(); diff --git a/src/KurrentDB.Client/Core/Exceptions/WrongExpectedVersionException.cs b/src/KurrentDB.Client/Core/Exceptions/WrongExpectedVersionException.cs index 34083b6b2..ab96a4cb9 100644 --- a/src/KurrentDB.Client/Core/Exceptions/WrongExpectedVersionException.cs +++ b/src/KurrentDB.Client/Core/Exceptions/WrongExpectedVersionException.cs @@ -47,7 +47,8 @@ public WrongExpectedVersionException(string streamName, StreamState expectedStre ActualVersion = actualStreamState.ToInt64(); } - public static WrongExpectedVersionException FromRpcException(RpcException ex) => FromRpcStatus(ex.GetRpcStatus()!); + public static WrongExpectedVersionException FromRpcException(RpcException ex) => + FromRpcStatus(ex.GetRpcStatus() ?? throw ex); public static WrongExpectedVersionException FromRpcStatus(Google.Rpc.Status ex) { var details = ex.GetDetail(); diff --git a/src/KurrentDB.Client/Streams/KurrentDBClient.MultiAppend.cs b/src/KurrentDB.Client/Streams/KurrentDBClient.MultiAppend.cs index ca2c1cb64..a3ff9440c 100644 --- a/src/KurrentDB.Client/Streams/KurrentDBClient.MultiAppend.cs +++ b/src/KurrentDB.Client/Streams/KurrentDBClient.MultiAppend.cs @@ -79,8 +79,7 @@ await session.RequestStream return new MultiStreamAppendResponse(response.Position, responses); } catch (RpcException ex) { - var status = ex.GetRpcStatus()!; - throw status.GetDetail() switch { + throw ex.GetRpcStatus()?.GetDetail() switch { { Reason: "STREAM_REVISION_CONFLICT" } => WrongExpectedVersionException.FromRpcException(ex), { Reason: "STREAM_TOMBSTONED" } => StreamTombstonedException.FromRpcException(ex), { Reason: "APPEND_RECORD_SIZE_EXCEEDED" } => AppendRecordSizeExceededException.FromRpcException(ex), diff --git a/src/KurrentDB.Client/Streams/MaximumAppendSizeExceededException.cs b/src/KurrentDB.Client/Streams/MaximumAppendSizeExceededException.cs index 3ec0dab13..444e5b83f 100644 --- a/src/KurrentDB.Client/Streams/MaximumAppendSizeExceededException.cs +++ b/src/KurrentDB.Client/Streams/MaximumAppendSizeExceededException.cs @@ -43,7 +43,8 @@ public AppendRecordSizeExceededException(string stream, string recordId, long si MaxSize = maxSize; } - public static AppendRecordSizeExceededException FromRpcException(RpcException ex) => FromRpcStatus(ex.GetRpcStatus()!); + public static AppendRecordSizeExceededException FromRpcException(RpcException ex) => + FromRpcStatus(ex.GetRpcStatus() ?? throw ex); public static AppendRecordSizeExceededException FromRpcStatus(Google.Rpc.Status ex) { var details = ex.GetDetail();