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

  1. Do not serialize through a CustomCreationConverter; remove the CanWrite override that re-enabled writing, or switch to a full JsonConverter that implements both directions.
  2. Use a different converter base (plain JsonConverter) if you need custom serialization too.
  3. 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

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


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