NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported means System.Text.Json found a class it could not decide how to create. The message lists the three shapes it accepts. In the case reproduced here the class had two constructors with parameters and no empty one, and marking one of them with [JsonConstructor] fixed it.

Pick the constructor whose parameters match the JSON properties, put [JsonConstructor] on it, and the same JSON deserializes with both values filled.

The error

Unhandled exception. System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'Contact'. Path: $ | LineNumber: 0 | BytePositionInLine: 1.
 ---> System.NotSupportedException: Deserialization of types without a parameterless constructor, a singular parameterized constructor, or a parameterized constructor annotated with 'JsonConstructorAttribute' is not supported. Type 'Contact'.
   --- End of inner exception stack trace ---
   at System.Text.Json.ThrowHelper.ThrowNotSupportedException(ReadStack& state, Utf8JsonReader& reader, Exception innerException)
...
   at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   at Program.<Main>$(String[] args) in C:\...\pc\Program.cs:line 13

Why it happens

The class that failed had read-only properties and two constructors:

public class Contact
{
    public Contact(string name) { Name = name; Email = ""; }
    public Contact(string name, string email) { Name = name; Email = email; }
    public string Name { get; }
    public string Email { get; }
}

Read against the message, Contact matches none of the three accepted shapes: there is no parameterless constructor, there is more than one parameterized constructor, and neither carries JsonConstructorAttribute. The message names the type (Type 'Contact') and the path $, the root object, because the failure happened before any property was read. The same message appears twice, once in the outer exception and once in the inner one.

The fix

public class FixedContact
{
    public FixedContact(string name) { Name = name; Email = ""; }
    [JsonConstructor]
    public FixedContact(string name, string email) { Name = name; Email = email; }
    public string Name { get; }
    public string Email { get; }
}

The JSON was {"Name":"Kwame Mensah","Email":"kwame@example.test"}, and dotnet run -- fix deserialized it into FixedContact and printed:

Kwame Mensah kwame@example.test

Both values arrived: the parameter names name and email were matched, ignoring case, to the properties Name and Email, which carry the JSON values, and the class body is otherwise the same as Contact. The attribute lives in System.Text.Json.Serialization, so the file needs that using. Put it on the constructor that takes every value you want from the JSON; here the two-parameter one, so Email is filled from the JSON instead of set to an empty string.

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 Contact class above and JsonSerializer.Deserialize<Contact>(json) with default options. Run with dotnet run for the error and dotnet run -- fix for the class with the attribute.

Frequently asked

Does System.Text.Json need a parameterless constructor?
Not necessarily. The error message accepts three shapes: a parameterless constructor, a single parameterized constructor, or a parameterized constructor marked with JsonConstructorAttribute. A class with two parameterized constructors and none marked fails.
Where do I put JsonConstructor?
On the one constructor System.Text.Json should call, normally the one that takes every value the JSON carries. Add using System.Text.Json.Serialization at the top of the file.
Why does the error say Path: $?
The dollar sign is the root of the JSON document. The serializer failed while deciding how to create the object, before it read any property, so the path points at the root.

More decoded errors in the Fixes category. A related System.Text.Json limit, for properties typed as an interface, is in Deserialization of interface or abstract types is not supported.