JamesNK/Newtonsoft.Json · error · JsonSerializationException
Converter cannot write specified value to JSON. {0} is requi
Error message
Converter cannot write specified value to JSON. {0} is required. What it means
Thrown by the sealed override JsonConverter<T>.WriteJson when the value handed to the converter is incompatible with the converter's generic type T. The base sealed method guards before delegating to the user-implemented WriteJson(writer, T?, serializer): if the value is non-null and not assignable to T (or null when T is not nullable), serialization is aborted with a JsonSerializationException naming the required type T. This protects the typed WriteJson from an invalid downcast.
Source
Thrown at Src/Newtonsoft.Json/JsonConverter.cs:95
}
/// <summary>
/// Converts an object to and from JSON.
/// </summary>
/// <typeparam name="T">The object type to convert.</typeparam>
public abstract class JsonConverter<T> : JsonConverter
{
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public sealed override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (!(value != null ? value is T : ReflectionUtils.IsNullable(typeof(T))))
{
throw new JsonSerializationException("Converter cannot write specified value to JSON. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
}
WriteJson(writer, (T?)value, serializer);
}
/// <summary>
/// Writes the JSON representation of the object.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
/// <param name="value">The value.</param>
/// <param name="serializer">The calling serializer.</param>
public abstract void WriteJson(JsonWriter writer, T? value, JsonSerializer serializer);
/// <summary>
/// Reads the JSON representation of the object.
/// </summary>
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
/// <param name="objectType">Type of the object.</param>
/// <param name="existingValue">The existing value of object being read.</param>View on GitHub (pinned to 4f73e74372)
Solutions
- Make CanConvert return true only for T (and Nullable<T> if intended) so the converter is never selected for other types.
- Scope the converter with [JsonConverter(typeof(MyConverter<T>))] on the exact property/type instead of adding it to settings.Converters.
- If you must handle null, ensure T is nullable (class or Nullable<T>) or override WriteJson to short-circuit nulls before the base guard.
Example fix
// before
public override bool CanConvert(Type objectType) => true; // matches everything
// after
public override bool CanConvert(Type objectType)
=> objectType == typeof(MyType) || Nullable.GetUnderlyingType(objectType) == typeof(MyType); Defensive patterns
Strategy: validation
Validate before calling
var converters = settings.Converters;
foreach (var c in converters)
{
if (value != null && !c.CanConvert(value.GetType()))
{
// do not let this converter handle value
}
} Type guard
static bool CanConvertStrict<T>(JsonConverter<T> c, Type objectType)
where T : class
=> objectType == typeof(T) || Nullable.GetUnderlyingType(objectType) == typeof(T); Prevention
- Implement CanConvert to match exactly the converter's T (and Nullable<T> if needed).
- Prefer attribute-scoped converters ([JsonConverter]) over global settings.Converters.
- Add unit tests asserting CanConvert returns false for sibling types.
When it happens
Trigger: A JsonConverter<T> is registered (via attributes or settings.Converters) but the serializer offers it a value whose runtime type is not T (or a nullable T when null is passed). Common when a converter is applied too broadly via JsonSerializerSettings.Converters and gets invoked for unrelated types, or when CanConvert returns true for types the converter cannot actually write.
Common situations: Registering a single generic converter globally for many types; a polymorphic property whose declared type differs from T; CanConvert over-matching (returning true for base types or interfaces); passing null to a converter whose T is a non-nullable value type.
Related errors
- Unexpected value type when writing binary: {0}
- Unexpected value when converting date. Expected DateTime or
- Expected date object value.
- Expected date object value.
- Expected Version object value
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/d353b5e612d2d49e.
Report an issue: GitHub.