JamesNK/Newtonsoft.Json · error · NotSupportedException
CustomCreationConverter should only be used while deserializ
Error message
CustomCreationConverter should only be used while deserializing.
What it means
Thrown by CustomCreationConverter<T>.WriteJson as a NotSupportedException. This converter family is read-only (CanWrite returns false); it exists to let you override Create(Type) to supply a target instance during deserialization. Serializing with it is unsupported by design, so calling WriteJson directly or forcing serialization through it triggers the error.
Source
Thrown at Src/Newtonsoft.Json/Converters/CustomCreationConverter.cs:49
namespace Newtonsoft.Json.Converters
{
/// <summary>
/// Creates a custom object.
/// </summary>
/// <typeparam name="T">The object type to convert.</typeparam>
[RequiresUnreferencedCode(MiscellaneousUtils.TrimWarning)]
[RequiresDynamicCode(MiscellaneousUtils.AotWarning)]
public abstract class CustomCreationConverter<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 override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
throw new NotSupportedException("CustomCreationConverter should only be used while deserializing.");
}
/// <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 override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
{
return null;
}
T value = Create(objectType);View on GitHub (pinned to 4f73e74372)
Solutions
- Do not serialize through a CustomCreationConverter; remove the CanWrite override that re-enabled writing, or switch to a full JsonConverter that implements both directions.
- Use a different converter base (plain JsonConverter) if you need custom serialization too.
- If you only need custom deserialization, keep CanWrite = false and rely on the default serializer for writing.
Example fix
// before: re-enabling write on a deserialize-only converter
public class FooConverter : CustomCreationConverter<IFoo>
{
public override bool CanWrite => true; // triggers NotSupportedException
public override IFoo Create(Type t) => new Foo();
}
// after: keep it read-only; use a separate converter for writing
public class FooConverter : CustomCreationConverter<IFoo>
{
public override IFoo Create(Type t) => new Foo();
// CanWrite stays false (default)
} Defensive patterns
Strategy: validation
Validate before calling
var conv = new MyCreationConverter();
if (conv is CustomCreationConverter<IFoo> ccc && ccc.CanWrite)
throw new InvalidOperationException("CustomCreationConverter must not be used for writing; keep CanWrite=false"); Type guard
static bool IsWriteSafeConverter(JsonConverter c) =>
!(c is CustomCreationConverter<IFoo> cc && cc.CanWrite); Try / catch
try { serializer.Serialize(writer, obj); }
catch (NotSupportedException ex) when (ex.Message.Contains("only be used while deserializing"))
{
throw new InvalidOperationException("A deserialize-only converter was used for serialization", ex);
} Prevention
- Keep CanWrite = false on CustomCreationConverter subclasses.
- Use a full JsonConverter if you need custom serialization in both directions.
- Do not call WriteJson directly on deserialize-only converters.
When it happens
Trigger: Subclassing CustomCreationConverter<T> and then serializing (not deserializing) an object whose contract routes through the converter while CanWrite has been overridden to true, or invoking WriteJson directly on the converter instance. Note the base CanWrite is false, so under normal serialization Newtonsoft skips WriteJson; hitting this means CanWrite was overridden or WriteJson was called manually.
Common situations: A developer overrides CanWrite => true on a CustomCreationConverter subclass thinking it will serialize polymorphically. Calling converter.WriteJson(...) directly in custom code. Confusing CustomCreationConverter (deserialize-only) with a full read/write converter.
Related errors
- Unexpected value type when writing binary: {0}
- No object created.
- Unexpected value when converting date. Expected DateTime or
- Expected date object value.
- Expected date object value.
AI-assisted analysis of JamesNK/Newtonsoft.Json@4f73e74372 (2026-08-07).
Data as JSON: /api/errors/2cf3f37cc07f0b41.
Report an issue: GitHub.