NotSupportedException: Serialization and deserialization of
'System.Reflection.MethodBase' instances is not supported. Path: $.TargetSite. is
what JsonSerializer.Serialize threw here when it was handed an
Exception object. The TargetSite property of the exception is a
MethodBase, and System.Text.Json refused it. Serialize a small record with the
fields you need instead of the exception itself.
A record holding the type name, the message and the stack trace as strings serialized without trouble in the same program, and that one line of JSON is what a log or an API response can carry in place of the exception object.
The error
Unhandled exception. System.NotSupportedException: Serialization and deserialization of 'System.Reflection.MethodBase' instances is not supported. Path: $.TargetSite.
---> System.NotSupportedException: Serialization and deserialization of 'System.Reflection.MethodBase' instances is not supported.
at System.Text.Json.Serialization.Converters.UnsupportedTypeConverter`1.Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
...
at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
at Program.<Main>$(String[] args) in C:\...\ex\Program.cs:line 20
Why it happens
The code caught an exception and passed it straight to the serializer:
Console.WriteLine(JsonSerializer.Serialize(caught));
caught was an InvalidOperationException thrown a few lines
earlier. The message names the property that stopped the serializer:
Path: $.TargetSite. TargetSite is the exception property that
holds the method that threw, typed as MethodBase. The first frame of the
inner exception is UnsupportedTypeConverter`1.Write, so the throw came from
the converter that wrote that property. No JSON was printed: the program stopped before
Console.WriteLine received anything.
The fix
var error = new ErrorReport(caught.GetType().FullName!, caught.Message, caught.StackTrace);
Console.WriteLine(JsonSerializer.Serialize(error));
...
public record ErrorReport(string Type, string Message, string? StackTrace);
Running dotnet run -- fix printed one line of JSON (the user folder in the path shortened):
{"Type":"System.InvalidOperationException","Message":"Order 1042 for Sofia Rossi could not be shipped.","StackTrace":" at Program.\u003CMain\u003E$(String[] args) in C:\\...\\ex\\Program.cs:line 6"}
Every property of ErrorReport is a string, so nothing in it reaches an
unsupported type. Note the stack trace in the output: it holds a full file path from the
machine that threw. Keep it for a private log; for anything a stranger can read, build
the record without the StackTrace field. Add fields such as an inner
exception's message the same way, as strings copied from the exception.
How it was reproduced
A console project from dotnet new console on .NET SDK 10.0.403
(net10.0, no extra packages; System.Text.Json is part of the framework). The
program throws and catches an InvalidOperationException with a fictional
order message, then calls JsonSerializer.Serialize(caught) with default
options. Run with dotnet run for the error and dotnet run -- fix
for the record.
Frequently asked
- Can System.Text.Json serialize an Exception?
- Not with default options in this test. JsonSerializer.Serialize on an InvalidOperationException threw NotSupportedException at the TargetSite property, whose type is System.Reflection.MethodBase.
- How do I log an exception as JSON in .NET?
- Copy the parts you need into a record of strings, such as the type name, the message and the stack trace, and serialize that record. In the test it produced one line of valid JSON.
- What does Path: $.TargetSite mean?
- It is the property of the exception object the serializer was writing when it stopped. TargetSite is the method that threw, and its type MethodBase is not supported by System.Text.Json.
More decoded errors in the Fixes category. Another serializer refusal that names a property path is A possible object cycle was detected.