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
- Guard with type.IsEnum before calling ParseEnum.
- Constrain generic methods with `where T : struct, Enum` (or `where TEnum : struct, IComparable, IFormattable, IConvertible` on older runtimes).
- Resolve and verify the concrete enum type before invoking.
- 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
- Constrain generic methods with `where T : struct, Enum`.
- Check type.IsEnum before invoking reflection-based enum APIs.
- Resolve and verify the concrete enum type at the boundary.
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
- Unexpected merge array handling when merging JSON.
- Target type {0} is not a value type or a non-abstract class.
- Could not get constructor for {0}.
- Property '{0}' does not have a getter.
- Enum name '{0}' already exists on enum '{1}'.
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/4d4d14a2d32de29e.
Report an issue: GitHub.