tui-cs/Terminal.Gui · error · JsonException

{propertyType.Name}: Converter "{converterType.FullName}" do

Error message

{propertyType.Name}: Converter "{converterType.FullName}" does not expose a compatible Write method.

What it means

Thrown by TryWriteWithDynamicConverter when a property-level JsonConverter (or the converter produced by a JsonConverterFactory) does not expose a Write method whose signature is exactly Write(Utf8JsonWriter, <propertyType>, JsonSerializerOptions). The converter is found by reflection (GetMethod(nameof(Write), [writer, propertyType, options])) and a null result means no matching overload exists — typically because the converter is typed against a base/different type, or is a JsonConverterFactory that returned a converter for the wrong type.

Source

Thrown at Terminal.Gui/Configuration/ScopeJsonConverter.cs:385

    private static bool TryWriteWithDynamicConverter (Utf8JsonWriter writer, Type propertyType, Type converterType, object value, JsonSerializerOptions options)
    {
        if (!RuntimeFeature.IsDynamicCodeSupported)
        {
            return false;
        }

        object converter = Activator.CreateInstance (converterType)!;

        if (converter is JsonConverterFactory factory && factory.CanConvert (propertyType))
        {
            converter = factory.CreateConverter (propertyType, options)!;
        }

        MethodInfo? writeMethod = converter.GetType ().GetMethod (nameof (Write), [typeof (Utf8JsonWriter), propertyType, typeof (JsonSerializerOptions)]);

        if (writeMethod is null)
        {
            throw new JsonException ($"{propertyType.Name}: Converter \"{converterType.FullName}\" does not expose a compatible Write method.");
        }

        try
        {
            writeMethod.Invoke (converter, [writer, value, options]);

            return true;
        }
        catch (TargetInvocationException e) when (e.InnerException is { })
        {
            throw new JsonException ($"{propertyType.Name}: Error writing property with converter \"{converterType.FullName}\".", e.InnerException);
        }
    }

    private static bool TryWriteWithKnownConverter (Utf8JsonWriter writer, Type propertyType, Type converterType, object? value, JsonSerializerOptions options)
    {
        if (converterType == typeof (ConcurrentDictionaryJsonConverter<ThemeScope>))
        {

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Make the converter generic or write a JsonConverterFactory that returns a converter parameterized by the exact property type.
  2. Align the property's declared type with the type the converter's Write method accepts.
  3. Drop the converter and let the source generator handle serialization for that property.

Example fix

// before
public class SchemeConverter : JsonConverter<SchemeBase> { ... }
[JsonConverter (typeof (SchemeConverter))]
public static MyScheme MyProp { get; set; } // MyScheme : SchemeBase -> no Write(MyScheme,...)

// after - use a factory
public class SchemeConverterFactory : JsonConverterFactory
{
    public override JsonConverter? CreateConverter (Type typeToConvert, JsonSerializerOptions o)
        => (JsonConverter?)Activator.CreateInstance (typeof (SchemeConverter<>).MakeGenericType (typeToConvert));
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Verify a converter exposes a compatible Write before relying on it
bool HasCompatibleWrite (object converter, Type propertyType)
    => converter.GetType ().GetMethod (nameof (JsonConverter<object>.Write),
        [typeof (Utf8JsonWriter), propertyType, typeof (JsonSerializerOptions)]) is not null;

Type guard

static bool ConverterSupportsWrite (JsonConverter c, Type propType)
    => c.GetType ().GetMethod ("Write", [typeof (Utf8JsonWriter), propType, typeof (JsonSerializerOptions)]) is not null;

Try / catch

try { sourcesManager.ToJson (scope); }
catch (JsonException ex) when (ex.Message.Contains ("does not expose a compatible Write method"))
{ /* replace converter with a factory or align types */ }

Prevention

When it happens

Trigger: A config property is decorated with [JsonConverter(typeof(SomeConverter))] where SomeConverter : JsonConverter<BaseType> but the property type is a derived type, so there is no Write(Utf8JsonWriter, DerivedType, ...) method. Also when a JsonConverterFactory.CreateConverter returns a converter that doesn't match propertyType.

Common situations: Reusing a generic converter across an inheritance hierarchy; a converter written for an interface applied to a concrete class; version skew where the converter targets an older type.

Related errors


AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13). Data as JSON: /api/errors/87c969de0bb29e11. Report an issue: GitHub.