{"record":{"id":"321e649bb7b4b0ba","repo":"JamesNK/Newtonsoft.Json","slug":"serialization-callback-1-in-type-0-must-re","errorCode":null,"errorMessage":"Serialization Callback '{1}' in type '{0}' must return void.","messagePattern":"Serialization Callback '(.+?)' in type '(.+?)' must return void\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs","lineNumber":1332,"sourceCode":"\n            if (currentCallback != null)\n            {\n                throw new JsonException(\"Invalid attribute. Both '{0}' and '{1}' in type '{2}' have '{3}'.\".FormatWith(CultureInfo.InvariantCulture, method, currentCallback, GetClrTypeFullName(method.DeclaringType!), attributeType));\n            }\n\n            if (prevAttributeType != null)\n            {\n                throw new JsonException(\"Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.\".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType!), method));\n            }\n\n            if (method.IsVirtual)\n            {\n                throw new JsonException(\"Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.\".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType!), attributeType));\n            }\n\n            if (method.ReturnType != typeof(void))\n            {\n                throw new JsonException(\"Serialization Callback '{1}' in type '{0}' must return void.\".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method));\n            }\n\n            if (attributeType == typeof(OnErrorAttribute))\n            {\n                if (parameters == null || parameters.Length != 2 || parameters[0].ParameterType != typeof(StreamingContext) || parameters[1].ParameterType != typeof(ErrorContext))\n                {\n                    throw new JsonException(\"Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'.\".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method, typeof(StreamingContext), typeof(ErrorContext)));\n                }\n            }\n            else\n            {\n                if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext))\n                {\n                    throw new JsonException(\"Serialization Callback '{1}' in type '{0}' must have a single parameter of type '{2}'.\".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method, typeof(StreamingContext)));\n                }\n            }\n\n            prevAttributeType = attributeType;","sourceCodeStart":1314,"sourceCodeEnd":1350,"githubUrl":"https://github.com/JamesNK/Newtonsoft.Json/blob/4f73e74372445108d2c1bda37b36e6f5e43402e0/Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs#L1314-L1350","documentation":"Serialization callback methods must return void. IsValidCallback checks method.ReturnType != typeof(void) and throws a JsonException (line 1332). The serializer ignores any return value, so a non-void return indicates a misdeclared hook.","triggerScenarios":"An On* callback method declared with a return type (int, bool, Task, the model type, etc.) instead of void.","commonSituations":"Reusing an existing helper that returns a value as a callback, or declaring the callback as async Task (async void or Task both break the void requirement).","solutions":["Change the method's return type to void.","If using async work, perform synchronous work in the callback or move async logic elsewhere (do not return Task from a callback)."],"exampleFix":"// before\npublic class Model {\n    [OnDeserialized]\n    internal bool OnDeserialized(StreamingContext c) => true; // throws\n}\n\n// after\npublic class Model {\n    [OnDeserialized]\n    internal void OnDeserialized(StreamingContext c) {}\n}","handlingStrategy":"validation","validationCode":"var attrs = new[] { typeof(OnSerializingAttribute), typeof(OnSerializedAttribute), typeof(OnDeserializingAttribute), typeof(OnDeserializedAttribute), typeof(OnErrorAttribute) };\nforeach (var m in typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))\n{\n    if (attrs.Any(a => m.IsDefined(a, false)) && m.ReturnType != typeof(void))\n        throw new InvalidOperationException($\"Callback method {m.Name} must return void.\");\n}","typeGuard":"static bool AllCallbacksReturnVoid(Type t)\n{\n    var attrs = new[] { typeof(OnSerializingAttribute), typeof(OnSerializedAttribute), typeof(OnDeserializingAttribute), typeof(OnDeserializedAttribute), typeof(OnErrorAttribute) };\n    return t.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)\n        .Where(m => attrs.Any(a => m.IsDefined(a, false)))\n        .All(m => m.ReturnType == typeof(void));\n}","tryCatchPattern":"try { JsonConvert.DeserializeObject<T>(json); }\ncatch (JsonException ex) when (ex.Message.Contains(\"must return void\"))\n{\n    // change the callback return type to void\n}","preventionTips":["Declare callback methods with a void return type.","Do not use async Task for callbacks; do synchronous work only."],"tags":["callback","attribute-validation","contract-resolution","return-type"],"analyzedSha":"4f73e74372445108d2c1bda37b36e6f5e43402e0","analyzedAt":"2026-08-07T06:10:08.596Z","schemaVersion":2},"datasetVersion":"2026-08-07T07:17:06.508Z"}