grpc-dotnet
grpc-dotnet copied to clipboard
Is it possible to intercept/handle errors thrown by Grpc.AspNetCore.Server.ServerCallHandler?
Hi, I'm working on error handling for a project and I'm trying to understand if it's possible to intercept or handle errors that seems to be thrown very early in the pipeline. I've tried interceptors, but seems like we never get there. Is there any suggested way to handle this kind of errors?
2020-10-14 14:18:08 [ERR] Grpc.AspNetCore.Server.ServerCallHandler
{"EventId":{"Id":14,"Name":"ErrorReadingMessage"},"RequestId":"0HM3G7CQSMESD:00000001","RequestPath":"/MyProject.SomeService/SetDisplayName","SpanId":"|bde9d0fa-4c539042cc801db0.","TraceId":"bde9d0fa-4c539042cc801db0","ParentId":""}
Error reading message.
System.FormatException: Unexpected Guid length: 37
at ProtoBuf.Internal.ThrowHelper.Format(String message) in /_/src/protobuf-net.Core/Internal/ThrowHelper.cs:line 34
at ProtoBuf.Internal.GuidHelper.Read(State& state) in /_/src/protobuf-net.Core/Internal/GuidHelper.cs:line 74
at proto_8(State& , SetDisplayNameRequest )
at ProtoBuf.Internal.Serializers.SimpleCompiledSerializer`1.ProtoBuf.Serializers.ISerializer<T>.Read(State& state, T value)
at ProtoBuf.ProtoReader.State.ReadAsRoot[T](T value, ISerializer`1 serializer)
at ProtoBuf.ProtoReader.State.DeserializeRoot[T](T value, ISerializer`1 serializer)
at ProtoBuf.Meta.TypeModel.Deserialize[T](ReadOnlySequence`1 source, T value, Object userState)
at ProtoBuf.Grpc.Configuration.ProtoBufMarshallerFactory.ContextualDeserialize[T](DeserializationContext context)
at Grpc.AspNetCore.Server.Internal.PipeExtensions.ReadSingleMessageAsync[T](PipeReader input, HttpContextServerCallContext serverCallContext, Func`2 deserializer)
2020-10-14 14:18:08 [ERR] Grpc.AspNetCore.Server.ServerCallHandler
{"EventId":{"Id":6,"Name":"ErrorExecutingServiceMethod"},"RequestId":"0HM3G7CQSMESD:00000001","RequestPath":"/MyProject.SomeService/SetDisplayName","SpanId":"|bde9d0fa-4c539042cc801db0.","TraceId":"bde9d0fa-4c539042cc801db0","ParentId":""}
Error when executing service method 'SetDisplayName'.
System.FormatException: Unexpected Guid length: 37
at ProtoBuf.Internal.ThrowHelper.Format(String message) in /_/src/protobuf-net.Core/Internal/ThrowHelper.cs:line 34
at ProtoBuf.Internal.GuidHelper.Read(State& state) in /_/src/protobuf-net.Core/Internal/GuidHelper.cs:line 74
at proto_8(State& , SetDisplayNameRequest )
at ProtoBuf.Internal.Serializers.SimpleCompiledSerializer`1.ProtoBuf.Serializers.ISerializer<T>.Read(State& state, T value)
at ProtoBuf.ProtoReader.State.ReadAsRoot[T](T value, ISerializer`1 serializer)
at ProtoBuf.ProtoReader.State.DeserializeRoot[T](T value, ISerializer`1 serializer)
at ProtoBuf.Meta.TypeModel.Deserialize[T](ReadOnlySequence`1 source, T value, Object userState)
at ProtoBuf.Grpc.Configuration.ProtoBufMarshallerFactory.ContextualDeserialize[T](DeserializationContext context)
at Grpc.AspNetCore.Server.Internal.PipeExtensions.ReadSingleMessageAsync[T](PipeReader input, HttpContextServerCallContext serverCallContext, Func`2 deserializer)
at Grpc.AspNetCore.Server.Internal.CallHandlers.UnaryServerCallHandler`3.HandleCallAsyncCore(HttpContext httpContext, HttpContextServerCallContext serverCallContext)
at Grpc.AspNetCore.Server.Internal.CallHandlers.ServerCallHandlerBase`3.<HandleCallAsync>g__AwaitHandleCall|8_0(HttpContextServerCallContext serverCallContext, Method`2 method, Task handleCall)
Or am I stuck with these errors and have to rely on Grpc.AspNetCore.Server.GrpcServiceOptions.EnableDetailedErrors to get a more detailed error? The issue with this method might be that I don't know which details that are leaked to the consumer, also the following error gives the status code Unknown, when it maybe could be a an InvalidArgument instead?
Thanks for your help. /Erik
What are you trying to handle exactly? What's the end goal?
In my example, protobuf-net.Grpc encounters a problem and throws an exception. I cannot find a way to catch this exception before it is turned into an error response and sent to the caller. One reason for doing this would be to attach a Correlation/TraceId to the response in order to help the caller with troubleshooting.
Interceptors are called after deserialization.
ASP.NET Core middleware can be added to the app to catch and handle the error.
Ok, that makes sense.
I feel confident that I've tried to handle this with regular middlewares, without success. Maybe I'm doing it wrong, do you have any sample/pseduo code?
Hmm, I think you're right that an exception doesn't get thrown. The gRPC server library catches exceptions and then sets a grpc-status trailer.
You could look at the response for a grpc-status trailer that is not zero in your middleware, but you won't get the originally thrown exception.
This might be a reason to add a gRPC global exception handler configuration option.
Yes, as you said the status code is in the trailer, but that seems to be it. Without the original exception there won't be much use unfortunately. And if there was an exception, would I be able to write a new response to the caller? The global exception handler sounds like the thing I'm asking for.