System.Text.Json.JsonException: The JSON value could not be converted to System.Int32. Path: $.id | LineNumber: 0 | BytePositionInLine: 10. means the JSON carries a string where your C# property is an int: {"id":"42"} instead of {"id":42}. The Path names the property, here $.id, so you know exactly which field to look at.

Send a number from the other side if you can. If you cannot change the sender, let the serializer read numbers written as strings with JsonNumberHandling.AllowReadingFromString, either for all properties in the options or for one property with an attribute.

The error

Unhandled exception. System.Text.Json.JsonException: The JSON value could not be converted to System.Int32. Path: $.id | LineNumber: 0 | BytePositionInLine: 10.
 ---> System.InvalidOperationException: Cannot get the value of a token type 'String' as a number.

It came from this call, with Order holding a single public int Id:

var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
string json = """{"id":"42"}""";
var order = JsonSerializer.Deserialize<Order>(json, options);

Why it happens

The JSON reader sees "42" as a string token. The converter for Int32 asks the reader for a number, the reader refuses, and the serializer wraps that refusal with the path and position of the value. By default System.Text.Json does not guess: a quoted value is text, whatever characters are inside the quotes.

Two details from the test change what you see. With default options and nothing else, {"id":"42"} did not fail at all: property names are case-sensitive, so id matched nothing and Id silently stayed 0. And ASP.NET Core uses the web defaults, which already read numbers from strings, so a minimal API endpoint taking Order accepted {"id":"42"} and answered {"id":42}. There the exception needs a string that is not a number, such as {"id":"forty-two"}:

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Date: Fri, 23 Oct 2026 04:36:49 GMT
Server: Kestrel
Transfer-Encoding: chunked

{"type":"https://tools.ietf.org/html/rfc9110#section-15.5.1","title":"Microsoft.AspNetCore.Http.BadHttpRequestException","status":400,"detail":"Failed to read parameter \"Order order\" from the request body as JSON.","exception":{"details": ...

Further into that body, the exception details carry the same JsonException with Path: $.id and BytePositionInLine: 17. It came from the Development environment with AddProblemDetails(). In Production the same request got a 400 with an empty body and nothing in the log at the default level, so reproduce it in Development to read the path.

The fix

Send the number: {"id":42} gave Id = 42. Or accept quoted numbers for every property:

var lenient = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true,
    NumberHandling = JsonNumberHandling.AllowReadingFromString
};
var order = JsonSerializer.Deserialize<Order>("""{"id":"42"}""", lenient);

Or for one property only:

public class LenientOrder
{
    [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
    public int Id { get; set; }
}

Both printed Id = 42. The option is not a cure-all: {"id":"forty-two"} still threw the same message with an inner FormatException, because the text is not a number. When the sender genuinely sends words, the property type is wrong, not the options; make it a string and parse it yourself.

How it was reproduced

A console project and an empty web project (dotnet new console, dotnet new web) on .NET SDK 10.0.402 with runtime 10.0.13, System.Text.Json from the shared framework and no packages, on Windows 11. The API listened on 127.0.0.1 and was called with curl 8.21.0. Order, LenientOrder and the values are the test's own.

Frequently asked

What does Path: $.id mean in a System.Text.Json exception?
It is the location of the value that failed, written as a JSON path: $ is the root object and .id is its id property. BytePositionInLine is where the reader stopped on that line, just after the bad value.
How do I deserialize a number stored as a string with System.Text.Json?
Set NumberHandling = JsonNumberHandling.AllowReadingFromString on JsonSerializerOptions, or put [JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)] on the one property. Quoted digits then read as numbers; quoted words still fail.
Why does ASP.NET Core accept a quoted number but my console app does not?
ASP.NET Core uses the web defaults, which include reading numbers from strings and case-insensitive names. A plain JsonSerializer call uses the general defaults, which do neither, so the same JSON behaves differently.

New to the format? JSON explained for beginners covers strings, numbers and why the quotes matter. More decoded errors in the Fixes category.