JamesNK/Newtonsoft.Json · error · Exception

Type {0} is not a collection.

Error message

Type {0} is not a collection.

What it means

Thrown by ReflectionUtils.GetCollectionItemType when a type implements IEnumerable<> but the resolved implementing generic type is itself a generic type definition (still open / unbound). This is an edge case where the element type could not be resolved to a concrete type. The collection lookup succeeded structurally but the type argument remains an open T.

Source

Thrown at Src/Newtonsoft.Json/Utilities/ReflectionUtils.cs:422

        /// Gets the type of the typed collection's items.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns>The type of the typed collection's items.</returns>
        public static Type? GetCollectionItemType(
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
            Type type)
        {
            ValidationUtils.ArgumentNotNull(type, nameof(type));

            if (type.IsArray)
            {
                return type.GetElementType();
            }
            if (ImplementsGenericDefinition(type, typeof(IEnumerable<>), out Type? genericListType))
            {
                if (genericListType!.IsGenericTypeDefinition())
                {
                    throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
                }

                return genericListType!.GetGenericArguments()[0];
            }
            if (typeof(IEnumerable).IsAssignableFrom(type))
            {
                return null;
            }

            throw new Exception("Type {0} is not a collection.".FormatWith(CultureInfo.InvariantCulture, type));
        }

        public static void GetDictionaryKeyValueTypes(
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
            Type dictionaryType,
            out Type? keyType,
            out Type? valueType)
        {

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Serialize/deserialize a closed generic instance (List<int>) rather than the open generic type definition.
  2. Provide a custom JsonConverter that knows the concrete element type.
  3. Ensure any TypeNameHandling-supplied type name resolves to a closed generic.

Example fix

// before
Type t = typeof(List<>); // open generic
var itemType = ReflectionUtils.GetCollectionItemType(t);

// after
Type t = typeof(List<int>); // closed generic
var itemType = ReflectionUtils.GetCollectionItemType(t);
Defensive patterns

Strategy: validation

Validate before calling

if (t.IsGenericType && t.ContainsGenericParameters)
    throw new ArgumentException("Pass a closed generic collection, not an open definition.");

Type guard

static bool IsClosedGenericCollection(Type t) => t.IsGenericType && !t.ContainsGenericParameters && typeof(IEnumerable).IsAssignableFrom(t);

Prevention

When it happens

Trigger: A type whose IEnumerable<> implementation is open (unresolved T) — abstract generic collection bases, or dynamically constructed open generic types reaching GetCollectionItemType. Often seen with reflection-emitted open generic types or misused TypeNameHandling producing open generics.

Common situations: Custom generic base classes used as collection types, open generic types leaking into the collection item-type resolution path, or deserializing with TypeNameHandling that resolves to an unbound generic.

Related errors


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