JamesNK/Newtonsoft.Json · error · JsonException
Serialization Error Callback
Error message
Serialization Error Callback '{1}' in type '{0}' must have two parameters of type '{2}' and '{3}'. What it means
An [OnError] callback must have exactly two parameters: a StreamingContext followed by an ErrorContext. IsValidCallback verifies parameter count and types and throws a JsonException (line 1339) otherwise. The error callback receives the serialization context and the error context so the handler can inspect and decide whether to swallow the error.
Solutions
- Give the [OnError] method the signature 'void M(StreamingContext context, ErrorContext errorContext)'.
- Decide whether to handle the error by setting errorContext.Handled = true inside the callback.
Example fix
// before
public class Model {
[OnError]
internal void OnError(Exception ex) {} // wrong signature -> throws
}
// after
public class Model {
[OnError]
internal void OnError(StreamingContext context, ErrorContext errorContext) {
errorContext.Handled = true;
}
} Defensive patterns
Strategy: validation
Validate before calling
foreach (var m in typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(m => m.IsDefined(typeof(OnErrorAttribute), false)))
{
var ps = m.GetParameters();
if (ps.Length != 2 || ps[0].ParameterType != typeof(StreamingContext) || ps[1].ParameterType != typeof(ErrorContext))
throw new InvalidOperationException($"OnError method {m.Name} must be (StreamingContext, ErrorContext).");
} Type guard
static bool OnErrorSignatureIsValid(MethodInfo m)
{
if (!m.IsDefined(typeof(OnErrorAttribute), false)) return true;
var ps = m.GetParameters();
return ps.Length == 2 && ps[0].ParameterType == typeof(StreamingContext) && ps[1].ParameterType == typeof(ErrorContext);
} Try / catch
try { JsonConvert.DeserializeObject<T>(json); }
catch (JsonException ex) when (ex.Message.Contains("Serialization Error Callback") && ex.Message.Contains("two parameters"))
{
// fix the OnError signature to (StreamingContext, ErrorContext)
} Prevention
- OnError methods must take (StreamingContext context, ErrorContext errorContext).
- Set errorContext.Handled = true to swallow specific errors.
When it happens
Trigger: An [OnError] method with zero, one, or three+ parameters, or with parameters of the wrong types (e.g. Exception instead of ErrorContext).
Common situations: Declaring an error handler with a single 'Exception' parameter by analogy with try/catch, or forgetting the StreamingContext parameter.
Related errors
- Invalid attribute. Both
- Invalid Callback. Method
- Serialization Callback
- Serialization Callback
- Virtual Method ' ' of type ' ' cannot be marked with ' '…
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/c46dbb8ef724dc50.
Report an issue: GitHub.
Appendix: source
Thrown at Src/Newtonsoft.Json/Serialization/DefaultContractResolver.cs:1339
{
throw new JsonException("Invalid Callback. Method '{3}' in type '{2}' has both '{0}' and '{1}'.".FormatWith(CultureInfo.InvariantCulture, prevAttributeType, attributeType, GetClrTypeFullName(method.DeclaringType!), method));
}
if (method.IsVirtual)
{
throw new JsonException("Virtual Method '{0}' of type '{1}' cannot be marked with '{2}' attribute.".FormatWith(CultureInfo.InvariantCulture, method, GetClrTypeFullName(method.DeclaringType!), attributeType));
}
if (method.ReturnType != typeof(void))
{
throw new JsonException("Serialization Callback '{1}' in type '{0}' must return void.".FormatWith(CultureInfo.InvariantCulture, GetClrTypeFullName(method.DeclaringType!), method));
}
if (attributeType == typeof(OnErrorAttribute))
{
if (parameters == null || parameters.Length != 2 || parameters[0].ParameterType != typeof(StreamingContext) || parameters[1].ParameterType != typeof(ErrorContext))
{
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)));
}
}
else
{
if (parameters == null || parameters.Length != 1 || parameters[0].ParameterType != typeof(StreamingContext))
{
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)));
}
}
prevAttributeType = attributeType;
return true;
}
internal static string GetClrTypeFullName(Type type)
{
if (type.IsGenericTypeDefinition() || !type.ContainsGenericParameters())View on GitHub (pinned to 4f73e74372)