InvalidOperationException: Each parameter in the deserialization constructor on type
'Member' must bind to an object property or field on deserialization means a
constructor parameter has no property with a matching name and type. In the case
reproduced here the parameter was called name while the property was
FullName; renaming the parameter to fullName fixed it.
Give every constructor parameter the same name as the property it fills (case does not matter, the message says so) and the same type. The message itself spells out the rule.
The error
Unhandled exception. System.InvalidOperationException: Each parameter in the deserialization constructor on type 'Member' must bind to an object property or field on deserialization. Each parameter name and type must match with a property or field on the object. Fields are only considered when 'JsonSerializerOptions.IncludeFields' is enabled. The name match can be case-insensitive.
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ConstructorParameterIncompleteBinding(Type parentType)
at System.Text.Json.Serialization.Converters.ObjectWithParameterizedConstructorConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
...
at System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
at Program.<Main>$(String[] args) in C:\...\bp\Program.cs:line 12
Why it happens
The class that failed:
public class Member
{
public Member(string name, int age) { FullName = name; Age = age; }
public string FullName { get; }
public int Age { get; }
}
age has a property called Age of the same type, so it matches.
name has no property called Name; the value it fills is stored
in FullName. The assignment FullName = name inside the
constructor body did not count: the run still threw, so the assignment in the body
did not make the parameter bind.
The message names the type ('Member') but not the parameter, so with a long
constructor check each parameter against the property list yourself.
Note what the message does not contain: no Path, no line number and no byte
position. The JSON in the run was {"FullName":"Lena Novak","Age":34}; the
mismatch is between the class and its own constructor.
The fix
public class FixedMember
{
public FixedMember(string fullName, int age) { FullName = fullName; Age = age; }
public string FullName { get; }
public int Age { get; }
}
Running dotnet run -- fix deserialized the same JSON and printed:
Lena Novak 34
The only change is the parameter name: name became fullName,
which matches FullName without regard to case. Both values reached the
object. The message also mentions fields: a parameter can bind to a field only when
JsonSerializerOptions.IncludeFields is enabled; that path was not tested here.
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
Member class above with a single constructor and
JsonSerializer.Deserialize<Member>(json) with default options. Run with
dotnet run for the error and dotnet run -- fix for the class with
the renamed parameter.
Frequently asked
- Which constructor parameter does not bind?
- The message names only the type. Compare each parameter with the properties: in the test, age matched the Age property and name had no Name property, because the value was stored in FullName.
- Do constructor parameter names have to match JSON property names?
- They have to match the class's property names, with the same type; the message says the name match can be case-insensitive. In the test, fullName matched FullName.
- How do I fix Each parameter in the deserialization constructor must bind?
- Rename the parameter to the name of the property it fills. Renaming name to fullName fixed the reproduced case.
More decoded errors in the Fixes category. A class with two constructors and none marked fails earlier, with Deserialization of types without a parameterless constructor is not supported.