JsonException: The JSON object contains a trailing comma at the end which is not supported in this mode. Change the reader options. means the JSON has a comma after the last property of an object, and the default System.Text.Json options refuse it. Remove the comma from the JSON, or set AllowTrailingCommas = true on JsonSerializerOptions.

"Change the reader options" points at that property. Setting it on the options passed to Deserialize made the same JSON load in the reproduction below.

The error

Unhandled exception. System.Text.Json.JsonException: The JSON object contains a trailing comma at the end which is not supported in this mode. Change the reader options. Path: $ | LineNumber: 3 | BytePositionInLine: 0.
 ---> System.Text.Json.JsonReaderException: The JSON object contains a trailing comma at the end which is not supported in this mode. Change the reader options. LineNumber: 3 | BytePositionInLine: 0.
   at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
...
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Program.<Main>$(String[] args) in C:\...\tc\Program.cs:line 18

Why it happens

The JSON in the test was this, a hand-edited object where the comma after the last property was left in place:

{
  "Name": "Aiko Tanaka",
  "City": "Lisbon",
}

The inner exception is a JsonReaderException: the failure comes from the reader, before any property is mapped to the class, which is why the message talks about reader options rather than about the Customer type. The position is the useful part. LineNumber: 3 | BytePositionInLine: 0 counts lines from zero, so line 3 is the fourth line, the closing brace that follows the comma.

The outer JsonException adds Path: $, the root object, since the comma sits directly inside it. The stack trace shows Utf8JsonReader.ConsumeNextTokenOrRollback and Utf8JsonReader.Read() under the converter that was reading the object, which matches the reader being the part that stopped.

The fix

var options = new JsonSerializerOptions { AllowTrailingCommas = true };
var fixedCustomer = JsonSerializer.Deserialize<Customer>(json, options)!;
Console.WriteLine($"{fixedCustomer.Name}, {fixedCustomer.City}");

Running dotnet run -- fix with the same JSON printed:

Aiko Tanaka, Lisbon

Both properties were read. If the JSON comes from a file you control, deleting the comma after "Lisbon" is the smaller change and needs no code change. Use AllowTrailingCommas when the JSON is written by people, for example a settings file, and you would rather accept the comma than fail.

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), a Customer class with two string properties and JsonSerializer.Deserialize<Customer>(json) with default options on the JSON above. Run with dotnet run for the error and dotnet run -- fix for the options with AllowTrailingCommas.

Frequently asked

How do I allow trailing commas in System.Text.Json?
Create the options with new JsonSerializerOptions { AllowTrailingCommas = true } and pass them to JsonSerializer.Deserialize. In the test the JSON with a comma after the last property then loaded.
What does Change the reader options mean?
The comma was rejected by the JSON reader, under the default options. AllowTrailingCommas on JsonSerializerOptions is the reader setting that accepts it.
Which line has the trailing comma?
The exception gives LineNumber and BytePositionInLine counted from zero. In the test LineNumber 3 pointed at the fourth line, the closing brace right after the comma.

More decoded errors in the Fixes category, where the other System.Text.Json posts sit in the EF Core, SQL Server and PostgreSQL group.