JamesNK/Newtonsoft.Json · error · JsonSerializationException
Converter cannot read JSON with the specified existing value
Error message
Converter cannot read JSON with the specified existing value. {0} is required. What it means
Thrown by the sealed override JsonConverter<T>.ReadJson when the existingValue argument is non-null but not assignable to the converter's generic type T. The base sealed method validates the existing value before forwarding it as a typed T? to the user ReadJson overload, so a mismatched existing value cannot cause an invalid cast inside the typed method. It is a JsonSerializationException naming the required type T.
Source
Thrown at Src/Newtonsoft.Json/JsonConverter.cs:121
/// <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>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
public sealed override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
bool existingIsNull = existingValue == null;
if (!(existingIsNull || existingValue is T))
{
throw new JsonSerializationException("Converter cannot read JSON with the specified existing value. {0} is required.".FormatWith(CultureInfo.InvariantCulture, typeof(T)));
}
return ReadJson(reader, objectType, existingIsNull ? default : (T?)existingValue, !existingIsNull, 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. If there is no existing value then <c>null</c> will be used.</param>
/// <param name="hasExistingValue">The existing value has a value.</param>
/// <param name="serializer">The calling serializer.</param>
/// <returns>The object value.</returns>
public abstract T? ReadJson(JsonReader reader, Type objectType, T? existingValue, bool hasExistingValue, JsonSerializer serializer);
/// <summary>
/// Determines whether this instance can convert the specified object type.
/// </summary>View on GitHub (pinned to 4f73e74372)
Solutions
- Restrict CanConvert to exactly T so the converter is not chosen for mismatched existing-value types.
- Pass null/default existingValue when populating through a converter, or ensure the object being populated is of type T.
- If you need broader handling, subclass JsonConverter (non-generic) and implement ReadJson with manual type checks.
Example fix
// before var obj = new OtherType(); serializer.Populate(reader, obj); // existingValue type != converter T // after var obj = new MyType(); // matches converter's T serializer.Populate(reader, obj);
Defensive patterns
Strategy: validation
Validate before calling
if (existingValue != null && converter is JsonConverter<T> && existingValue is not T)
{
existingValue = null; // or default(T)
} Type guard
static bool ExistingValueCompatible<T>(object existing, JsonConverter<T> _)
=> existing is null or T; Prevention
- Pass null existingValue to Populate when the target is a fresh T.
- Keep CanConvert narrow so converters are not applied to mismatched types.
- Prefer the non-generic JsonConverter base when handling heterogeneous types.
When it happens
Trigger: Deserialization with a JsonConverter<T> where the serializer passes an existingValue of a different type — e.g. populating an existing object whose declared type differs from T, or using JsonSerializer.Populate / a non-default current value with a converter that only accepts T. Also when CanConvert matches a type other than the one actually constructed for the existing value.
Common situations: Using Populate with converters; polymorphic deserialization where the runtime existing value's type does not match the converter's T; converters shared across a base type hierarchy.
Related errors
- Expected Bytes but got {0}.
- Unexpected value type when writing binary: {0}
- No object created.
- Expected JSON property '{0}'.
- Unexpected value when converting date. Expected DateTime or
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/cc765ca51301fd66.
Report an issue: GitHub.