JamesNK/Newtonsoft.Json · error · JsonException

Serialization Error Callback '{1}' in type '{0}' must have t

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.

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)

Solutions

  1. Give the [OnError] method the signature 'void M(StreamingContext context, ErrorContext errorContext)'.
  2. 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

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


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