{"record":{"id":"78e1975add315895","repo":"JamesNK/Newtonsoft.Json","slug":"invalid-extension-data-attribute-on-0-member-78e197","errorCode":null,"errorMessage":"Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary<string, JToken>.","messagePattern":"Invalid extension data attribute on '(.+?)'\\. Member '(.+?)' type must implement IDictionary<string, JToken>\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs","lineNumber":488,"sourceCode":"                if (!ReflectionUtils.CanReadMemberValue(m, true))\n                {\n                    throw new JsonException(\"Invalid extension data attribute on '{0}'. Member '{1}' must have a getter.\".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType!), m.Name));\n                }\n\n                Type t = ReflectionUtils.GetMemberUnderlyingType(m);\n\n                if (ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type? dictionaryType))\n                {\n                    Type keyType = dictionaryType.GetGenericArguments()[0];\n                    Type valueType = dictionaryType.GetGenericArguments()[1];\n\n                    if (keyType.IsAssignableFrom(typeof(string)) && valueType.IsAssignableFrom(typeof(JToken)))\n                    {\n                        return true;\n                    }\n                }\n\n                throw new JsonException(\"Invalid extension data attribute on '{0}'. Member '{1}' type must implement IDictionary<string, JToken>.\".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(m.DeclaringType!), m.Name));\n            });\n\n            return extensionDataMember;\n        }\n\n        private static void SetExtensionDataDelegates(JsonObjectContract contract, MemberInfo member)\n        {\n            JsonExtensionDataAttribute? extensionDataAttribute = ReflectionUtils.GetAttribute<JsonExtensionDataAttribute>(member);\n            if (extensionDataAttribute == null)\n            {\n                return;\n            }\n\n            Type t = ReflectionUtils.GetMemberUnderlyingType(member);\n\n            ReflectionUtils.ImplementsGenericDefinition(t, typeof(IDictionary<,>), out Type? dictionaryType);\n\n            Type keyType = dictionaryType!.GetGenericArguments()[0];","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/JamesNK/Newtonsoft.Json/blob/4f73e74372445108d2c1bda37b36e6f5e43402e0/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs#L470-L506","documentation":"The [JsonExtensionData] member's type must implement IDictionary<string, JToken> (key assignable from string, value assignable from JToken). Contract resolution checks the generic dictionary arguments and throws a JsonException (line 488) if the member is any other collection/value type. Extension data is stored as JToken values keyed by string, so incompatible dictionary types are rejected.","triggerScenarios":"Decorating a member of the wrong type, e.g. [JsonExtensionData] Dictionary<string, object>, List<KeyValuePair<...>>, Dictionary<int, JToken>, or a non-dictionary field.","commonSituations":"Assuming [JsonExtensionData] accepts Dictionary<string, object> (it does not), or copy-pasting the attribute onto an unrelated collection member.","solutions":["Change the member type to IDictionary<string, JToken> or Dictionary<string, JToken>.","If you need strongly-typed values, deserialize into JToken and convert in an OnDeserialized callback rather than changing the dictionary type."],"exampleFix":"// before\n[JsonExtensionData]\npublic Dictionary<string, object> Extra { get; set; } // wrong value type\n\n// after\n[JsonExtensionData]\npublic Dictionary<string, JToken> Extra { get; set; } = new Dictionary<string, JToken>();","handlingStrategy":"validation","validationCode":"foreach (var p in typeof(T).GetProperties().Where(p => p.IsDefined(typeof(JsonExtensionDataAttribute), false)))\n{\n    var t = p.PropertyType;\n    var ok = t.GetInterfaces().Concat(new[] { t })\n        .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>)\n            && i.GetGenericArguments()[0] == typeof(string)\n            && typeof(JToken).IsAssignableFrom(i.GetGenericArguments()[1]));\n    if (!ok) throw new InvalidOperationException($\"{p.Name} must be IDictionary<string, JToken>.\");\n}","typeGuard":"static bool IsValidExtensionDataType(Type t)\n{\n    return t.GetInterfaces().Concat(new[] { t }).Any(i =>\n        i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IDictionary<,>)\n        && i.GetGenericArguments()[0] == typeof(string)\n        && typeof(JToken).IsAssignableFrom(i.GetGenericArguments()[1]));\n}","tryCatchPattern":"try { JsonConvert.DeserializeObject<T>(json); }\ncatch (JsonException ex) when (ex.Message.Contains(\"IDictionary<string, JToken>\"))\n{\n    // change the member type to IDictionary<string, JToken>\n}","preventionTips":["Use IDictionary<string, JToken> or Dictionary<string, JToken> for extension data.","Avoid Dictionary<string, object>; it is not supported."],"tags":["extension-data","attribute-validation","contract-resolution","type-mismatch"],"analyzedSha":"4f73e74372445108d2c1bda37b36e6f5e43402e0","analyzedAt":"2026-08-07T06:10:08.596Z","schemaVersion":2},"datasetVersion":"2026-08-07T07:17:06.508Z"}