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
- Make the converter generic or write a JsonConverterFactory that returns a converter parameterized by the exact property type.
- Align the property's declared type with the type the converter's Write method accepts.
- 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
- Type converters' Write against the exact property type, not a base type.
- Use JsonConverterFactory when one converter logic spans multiple types.
- Add a reflection-based smoke test that checks every config converter exposes Write for its property type.
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
- {propertyType.Name}: Error writing property with converter "
- {propertyType.Name}: Error reading property with converter "
- Unexpected StartObject token when parsing Attribute: {reader
- {propertyName}: Both Foreground and Background colors must b
- {propertyName}: Json error in ScopeJsonConverter
AI-assisted analysis of tui-cs/Terminal.Gui@2e47b11478 (2026-08-13).
Data as JSON: /api/errors/87c969de0bb29e11.
Report an issue: GitHub.