JamesNK/Newtonsoft.Json · error · ArgumentException

Target type {0} is not a value type or a non-abstract class.

Error message

Target type {0} is not a value type or a non-abstract class.

What it means

ConvertUtils.Convert throws this (as ArgumentException) when TryConvertInternal returns ConvertResult.NotInstantiableType (ConvertUtils.cs:390-391). That happens when the target type is an interface, an open generic type definition, or an abstract class (ConvertUtils.cs:581-585) — none of which can be instantiated or meaningfully converted into.

Source

Thrown at Src/Newtonsoft.Json/Utilities/ConvertUtils.cs:391

        {
            Success = 0,
            CannotConvertNull = 1,
            NotInstantiableType = 2,
            NoValidConversion = 3
        }

        [RequiresUnreferencedCode(MiscellaneousUtils.TrimWarning)]
        [RequiresDynamicCode(MiscellaneousUtils.AotWarning)]
        public static object Convert(object initialValue, CultureInfo culture, Type targetType)
        {
            switch (TryConvertInternal(initialValue, culture, targetType, out object? value))
            {
                case ConvertResult.Success:
                    return value!;
                case ConvertResult.CannotConvertNull:
                    throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType));
                case ConvertResult.NotInstantiableType:
                    throw new ArgumentException("Target type {0} is not a value type or a non-abstract class.".FormatWith(CultureInfo.InvariantCulture, targetType), nameof(targetType));
                case ConvertResult.NoValidConversion:
                    throw new InvalidOperationException("Can not convert from {0} to {1}.".FormatWith(CultureInfo.InvariantCulture, initialValue.GetType(), targetType));
                default:
                    throw new InvalidOperationException("Unexpected conversion result.");
            }
        }

        [RequiresUnreferencedCode(MiscellaneousUtils.TrimWarning)]
        [RequiresDynamicCode(MiscellaneousUtils.AotWarning)]
        private static bool TryConvert(object? initialValue, CultureInfo culture, Type targetType, out object? value)
        {
            try
            {
                if (TryConvertInternal(initialValue, culture, targetType, out value) == ConvertResult.Success)
                {
                    return true;
                }

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Pass a concrete, closed type (List<object>, a concrete subclass) as the target.
  2. Resolve the concrete runtime type before conversion (e.g. via a factory or type mapping).
  3. If the source is JSON, configure JsonSerializerSettings/ContractResolver to pick a concrete type for the property.
  4. Validate targetType with !targetType.IsAbstract && !targetType.IsInterface && !targetType.IsGenericTypeDefinition before calling Convert.

Example fix

// before
object o = ConvertUtils.Convert(value, culture, typeof(IEnumerable));
// after
object o = ConvertUtils.Convert(value, culture, typeof(List<object>));
Defensive patterns

Strategy: validation

Validate before calling

// Reject interfaces/open-generics/abstract types before calling Convert.
static void EnsureInstantiable(Type t) {
    if (t.IsInterface || t.IsAbstract || t.IsGenericTypeDefinition)
        throw new ArgumentException($"Target type {t} must be a concrete, closed type.");
}

Type guard

static bool IsInstantiable(Type t) => !t.IsInterface && !t.IsAbstract && !t.IsGenericTypeDefinition;

Try / catch

try { return ConvertUtils.Convert(value, culture, targetType); } catch (ArgumentException ex) when (ex.Message.Contains("not a value type or a non-abstract class")) { /* resolve a concrete subtype */ }

Prevention

When it happens

Trigger: Calling ConvertUtils.Convert (directly or via the deserialization pipeline) with targetType equal to an interface (IEnumerable, IList), an open generic (typeof(List<>)), or an abstract base class.

Common situations: Reflection/generic code that loses the concrete type and passes an interface or open generic as the target; misconfigured contracts that resolve a property to an abstract type; dynamic typing losing closure.

Related errors


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