Runtime: System.Text.Json - can't serialize exception

Created on 5 Oct 2020  路  4Comments  路  Source: dotnet/runtime

Description

We're trying to use System.Text.Json for serialization and deserialization inside our API project with GraphQL. Sometimes the response object from GraphQL contains errors (exceptions). And serialization of this object fails. So I've come up with a simplified example for the problem:

static void Main(string[] args)
        {
            try
            {
                throw new InvalidOperationException("New exception");
            }
            catch (Exception ex)
            {
                var str = JsonSerializer.Serialize(ex);
            }
            Console.WriteLine("Hello World!");
        }

The code above throws System.NotSupportedException: Serialization and deserialization of 'System.Type' instances are not supported

Expected

Exceptions are serialized

Workaround

Use Newtonsoft serializer in ASP.NET pipeline.

area-System.Text.Json

Most helpful comment

It has been concluded in the past that (de)serialization of System.Type is not secure https://github.com/dotnet/runtime/issues/31567#issuecomment-558335944, therefore the are no plans on changing/removing the exception that you are reporting.

Unfortunately, right now I don't have any workaround other than just moving to Newtonsoft

@AlexeyKhrenov Does adding a converter for Exceptions solves your scenario?

class ExceptionConverter : JsonConverter<Exception>
{
    public override Exception Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, Exception value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteString("Message", value.Message);
        // Add any other propoerties that you may want to include in your JSON.
        // ...
        writer.WriteEndObject();
    }
}

Then add such converter to your JsonSerializerOptions:

static void Main(string[] args)
{
    var options = new JsonSerializerOptions();
    options.Converters.Add(new ExceptionConverter());

    try
    {
        throw new InvalidOperationException("New exception");
    }
    catch (Exception ex)
    {
        var str = JsonSerializer.Serialize(ex, options);
    }
    Console.WriteLine("Hello World!");
}

I get a completely different error in dotnetfiddle, which might be its own problem...

@Clockwork-Muse that error is because serialization of your Exception instance is falling into an infinite loop. Throwing for System.Type is new behavior on 5.0.

All 4 comments

.... first of all, you generally shouldn't return raw exceptions in an API. Not only because of potential security vulnerabilities, but also simply because there's going to be a bunch of implementation details which are _in no way relevant_ to your callers (line numbers, full call stack). They should get logged, and some generic "we messed up" error returned (HTTP 500, maybe).

If this is in reference to your caller doing something not supported by your API (calling Add on a collection with the maximum number of items, for example), that's not exceptional. That's a "foreseeable" error on your end. You should be returning some sort of specific error type relevant to the operation at hand. Since graphql mostly uses JSON you might want to look into the problem details RFC.

I get a completely different error in dotnetfiddle, which might be its own problem...

You're absolutely right. What was stated is absolutely right in broad sense. But I wouldn't like to share the whole picture related to our API in this narrow discussion. And also there's no need for people to give any recomendations when they don't have the whole picture and especially when the recomendation doesn't relate to the subject of the topic.
As for the defence of legitimacy of cases when I really need to serialize an exception I can think out a lot of cases: when I'm trying to log an exception as JSON and etc.
I would be happy to have a possibility to just specify inside JsonSerializerOptions that System.Type should be ignored during serialization
Unfortunately, right now I don't have any workaround other than just moving to Newtonsoft

It has been concluded in the past that (de)serialization of System.Type is not secure https://github.com/dotnet/runtime/issues/31567#issuecomment-558335944, therefore the are no plans on changing/removing the exception that you are reporting.

Unfortunately, right now I don't have any workaround other than just moving to Newtonsoft

@AlexeyKhrenov Does adding a converter for Exceptions solves your scenario?

class ExceptionConverter : JsonConverter<Exception>
{
    public override Exception Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, Exception value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        writer.WriteString("Message", value.Message);
        // Add any other propoerties that you may want to include in your JSON.
        // ...
        writer.WriteEndObject();
    }
}

Then add such converter to your JsonSerializerOptions:

static void Main(string[] args)
{
    var options = new JsonSerializerOptions();
    options.Converters.Add(new ExceptionConverter());

    try
    {
        throw new InvalidOperationException("New exception");
    }
    catch (Exception ex)
    {
        var str = JsonSerializer.Serialize(ex, options);
    }
    Console.WriteLine("Hello World!");
}

I get a completely different error in dotnetfiddle, which might be its own problem...

@Clockwork-Muse that error is because serialization of your Exception instance is falling into an infinite loop. Throwing for System.Type is new behavior on 5.0.

Thank you, @Jozkee ! Implementing a custom JsonConverter will definetely solve the issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sahithreddyk picture sahithreddyk  路  3Comments

iCodeWebApps picture iCodeWebApps  路  3Comments

yahorsi picture yahorsi  路  3Comments

GitAntoinee picture GitAntoinee  路  3Comments

aggieben picture aggieben  路  3Comments