JamesNK/Newtonsoft.Json · error · ArgumentException
Property does not have a getter.
Error message
Property does not have a getter.
What it means
ExpressionReflectionDelegateFactory.CreateGet<T>(PropertyInfo) (ExpressionReflectionDelegateFactory.cs:228-261) compiles an expression tree to read a property. It calls propertyInfo.GetGetMethod(true); if the property has no get accessor (write-only), it throws ArgumentException at ExpressionReflectionDelegateFactory.cs:241. This is the Expression-based counterpart of the DynamicReflectionDelegateFactory error [251], used on platforms where Expression trees are preferred over ReflectionEmit (non-NET20/35).
Source
Thrown at Src/Newtonsoft.Json/Utilities/ExpressionReflectionDelegateFactory.cs:241
return () => (T)Activator.CreateInstance(type)!;
}
}
[RequiresDynamicCode(MiscellaneousUtils.AotWarning)]
public override Func<T, object?> CreateGet<T>(PropertyInfo propertyInfo)
{
ValidationUtils.ArgumentNotNull(propertyInfo, nameof(propertyInfo));
Type instanceType = typeof(T);
Type resultType = typeof(object);
ParameterExpression parameterExpression = Expression.Parameter(instanceType, "instance");
Expression resultExpression;
MethodInfo? getMethod = propertyInfo.GetGetMethod(true);
if (getMethod == null)
{
throw new ArgumentException("Property does not have a getter.");
}
if (getMethod.IsStatic)
{
resultExpression = Expression.MakeMemberAccess(null, propertyInfo);
}
else
{
Expression readParameter = EnsureCastExpression(parameterExpression, propertyInfo.DeclaringType!);
resultExpression = Expression.MakeMemberAccess(readParameter, propertyInfo);
}
resultExpression = EnsureCastExpression(resultExpression, resultType);
LambdaExpression lambdaExpression = Expression.Lambda(typeof(Func<T, object>), resultExpression, parameterExpression);
Func<T, object?> compiled = (Func<T, object?>)lambdaExpression.Compile();View on GitHub (pinned to 4f73e74372)
Solutions
- Add a getter to the property (private getters are accepted because GetGetMethod(true) is used).
- Annotate the write-only property with [JsonIgnore] so serialization skips it.
- Configure an IContractResolver that excludes properties where !CanRead.
- Expose the value through a separate readable member.
Example fix
// before
public string Secret { set; } // write-only -> throws on serialize
// after
[JsonIgnore]
public string Secret { set; } Defensive patterns
Strategy: validation
Validate before calling
// Exclude write-only properties from serialization contracts.
foreach (var prop in type.GetProperties()) {
if (prop.GetGetMethod(true) == null) continue; // write-only, skip
/* build getter via ExpressionReflectionDelegateFactory */
} Type guard
static bool HasGetter(System.Reflection.PropertyInfo p) => p.GetGetMethod(true) != null;
Try / catch
try { serializer.Serialize(writer, value); } catch (ArgumentException ex) when (ex.Message.Contains("does not have a getter")) { /* mark the offending property [JsonIgnore] */ } Prevention
- Mark write-only properties with [JsonIgnore].
- Use a contract resolver that skips properties where !CanRead.
- Add a getter (even a private one) to any property you intend to serialize.
When it happens
Trigger: The serializer's contract creation attempts to build a getter for a write-only property (only a setter) on a runtime that selects ExpressionReflectionDelegateFactory.
Common situations: Write-only properties (set; only); fluent-builder APIs; generated proxies with asymmetric accessors; intent-restricted setters; same root cause as [251] but on a different delegate factory.
Related errors
- Property '{0}' does not have a getter.
- Could not get constructor for {0}.
- Could not create getter for {0}. ByRef return values are not
- Error setting value to '{0}' on '{1}'.
- Error getting value from '{0}' on '{1}'.
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/769c40668559d8d1.
Report an issue: GitHub.