JamesNK/Newtonsoft.Json · error · ArgumentException

Type provided must be an Enum.

Error message

Type provided must be an Enum.

What it means

ParseEnum (EnumUtils.cs:259-381) requires enumType to actually be an enum. It checks enumType.IsEnum() at EnumUtils.cs:264-267 and throws ArgumentException if the type is a class/struct/interface/primitive — only true enum types carry the member/value mapping ParseEnum relies on.

Source

Thrown at Src/Newtonsoft.Json/Utilities/EnumUtils.cs:266

                    return (ulong)(int)value;
                case PrimitiveTypeCode.UInt64:
                    return (ulong)value;
                case PrimitiveTypeCode.Int64:
                    return (ulong)(long)value;
                // All unsigned types will be directly cast
                default:
                    throw new InvalidOperationException("Unknown enum type.");
            }
        }

        public static object ParseEnum(Type enumType, NamingStrategy? namingStrategy, string value, bool disallowNumber)
        {
            ValidationUtils.ArgumentNotNull(enumType, nameof(enumType));
            ValidationUtils.ArgumentNotNull(value, nameof(value));

            if (!enumType.IsEnum())
            {
                throw new ArgumentException("Type provided must be an Enum.", nameof(enumType));
            }

            EnumInfo entry = ValuesAndNamesPerEnum.Get(new StructMultiKey<Type, NamingStrategy?>(enumType, namingStrategy));
            string[] enumNames = entry.Names;
            string[] resolvedNames = entry.ResolvedNames;
            ulong[] enumValues = entry.Values;

            // first check if the entire text (including commas) matches a resolved name
            int? matchingIndex = FindIndexByName(resolvedNames, value, 0, value.Length, StringComparison.Ordinal);
            if (matchingIndex != null)
            {
                return Enum.ToObject(enumType, enumValues[matchingIndex.Value]);
            }

            int firstNonWhitespaceIndex = -1;
            for (int i = 0; i < value.Length; i++)
            {
                if (!char.IsWhiteSpace(value[i]))

View on GitHub (pinned to 4f73e74372)

Solutions

  1. Guard with type.IsEnum before calling ParseEnum.
  2. Constrain generic methods with `where T : struct, Enum` (or `where TEnum : struct, IComparable, IFormattable, IConvertible` on older runtimes).
  3. Resolve and verify the concrete enum type before invoking.
  4. Return an error/default rather than calling ParseEnum on non-enum types.

Example fix

// before
object Parse<T>(string s) => EnumUtils.ParseEnum(typeof(T), null, s, false); // T may be non-enum
// after
object Parse<T>(string s) {
    if (!typeof(T).IsEnum) throw new InvalidOperationException($"{typeof(T)} is not an enum.");
    return EnumUtils.ParseEnum(typeof(T), null, s, false);
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard before calling ParseEnum.
if (!enumType.IsEnum) throw new ArgumentException($"{enumType} is not an enum.");

Type guard

static bool IsEnumType(Type t) => t.IsEnum;

Try / catch

try { return EnumUtils.ParseEnum(enumType, null, value, false); } catch (ArgumentException ex) when (ex.Message.Contains("must be an Enum")) { /* caller passed wrong type */ }

Prevention

When it happens

Trigger: Passing a non-enum Type to ParseEnum — typeof(int), typeof(string), typeof(MyClass), or an open generic — typically from reflection/generic code that has lost the enum constraint.

Common situations: Generic deserialization helpers that accept arbitrary Type parameters; misconfigured converters that pass the wrong type; dynamically resolved types that unexpectedly resolve to a non-enum.

Related errors


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