JamesNK/Newtonsoft.Json · error · ArgumentException

Property '{0}' does not have a getter.

Error message

Property '{0}' does not have a getter.

What it means

GenerateCreateGetPropertyIL (DynamicReflectionDelegateFactory.cs:307-323) builds a compiled getter delegate for a PropertyInfo. It calls propertyInfo.GetGetMethod(true); if the property has no get accessor (write-only property), getMethod is null and it throws ArgumentException at DynamicReflectionDelegateFactory.cs:312. This factory is used on platforms where ReflectionEmit is available.

Source

Thrown at Src/Newtonsoft.Json/Utilities/DynamicReflectionDelegateFactory.cs:312

        }

        [RequiresDynamicCode(MiscellaneousUtils.AotWarning)]
        public override Func<T, object?> CreateGet<T>(PropertyInfo propertyInfo)
        {
            DynamicMethod dynamicMethod = CreateDynamicMethod("Get" + propertyInfo.Name, typeof(object), new[] { typeof(T) }, propertyInfo.DeclaringType!);
            ILGenerator generator = dynamicMethod.GetILGenerator();

            GenerateCreateGetPropertyIL(propertyInfo, generator);

            return (Func<T, object?>)dynamicMethod.CreateDelegate(typeof(Func<T, object?>));
        }

        private void GenerateCreateGetPropertyIL(PropertyInfo propertyInfo, ILGenerator generator)
        {
            MethodInfo? getMethod = propertyInfo.GetGetMethod(true);
            if (getMethod == null)
            {
                throw new ArgumentException("Property '{0}' does not have a getter.".FormatWith(CultureInfo.InvariantCulture, propertyInfo.Name));
            }

            if (!getMethod.IsStatic)
            {
                generator.PushInstance(propertyInfo.DeclaringType!);
            }

            generator.CallMethod(getMethod);
            generator.BoxIfNeeded(propertyInfo.PropertyType);
            generator.Return();
        }

        [RequiresDynamicCode(MiscellaneousUtils.AotWarning)]
        public override Func<T, object?> CreateGet<T>(FieldInfo fieldInfo)
        {
            if (fieldInfo.IsLiteral)
            {
                object constantValue = fieldInfo.GetValue(null)!;

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Add a getter to the property (even a private one, since GetGetMethod(true) retrieves non-public).
  2. Mark the write-only property with [JsonIgnore] so the serializer skips it.
  3. Use a custom IContractResolver/ContractResolver that excludes properties without a getter (CanRead == false).
  4. Map the value through a different, 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

// Skip write-only properties when building a contract.
foreach (var prop in type.GetProperties()) {
    if (prop.GetGetMethod(true) == null) continue; // write-only
    /* build getter */
}

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 offending property [JsonIgnore] */ }

Prevention

When it happens

Trigger: The serializer's contract creation tries to build a getter for a write-only property (one with only a setter) on a platform using the DynamicReflectionDelegateFactory.

Common situations: Properties intentionally exposed as write-only (set; only); fluent-builder-style APIs; generated proxy types with asymmetric accessors.

Related errors


AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07). Data as JSON: /api/errors/50738ab37f98cd73. Report an issue: GitHub.