tui-cs/Terminal.Gui · error · JsonException

{propertyType.Name}: Error writing property with converter "

Error message

{propertyType.Name}: Error writing property with converter "{converterType.FullName}".

What it means

Thrown by TryWriteWithDynamicConverter when the converter's Write method was found and invoked but threw an exception (surfaced as TargetInvocationException with a non-null InnerException). The InnerException is rewrapped as a JsonException so callers see the property type, the converter type, and the real underlying error. This is the write-side analog of error 84.

Source

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

            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>))
        {
            new ConcurrentDictionaryJsonConverter<ThemeScope> ().Write (writer, (ConcurrentDictionary<string, ThemeScope>)value!, options);

            return true;
        }

        if (converterType == typeof (DictionaryJsonConverter<Scheme?>))
        {
            new DictionaryJsonConverter<Scheme?> ().Write (writer, (Dictionary<string, Scheme?>)value!, options);

            return true;
        }

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Read the InnerException message printed alongside this JsonException to find the real failure in the converter, then fix the converter to handle that case.
  2. Ensure the property value is in a state the converter expects before serializing (initialize defaults, validate enums).
  3. If the converter is third-party, avoid assigning values it cannot serialize, or replace it with a source-generated type.

Example fix

// before - converter throws on null
public override void Write (Utf8JsonWriter w, Foo v, JsonSerializerOptions o)
    => w.WriteStringValue (v.Name); // NullReferenceException if v is null

// after
public override void Write (Utf8JsonWriter w, Foo? v, JsonSerializerOptions o)
{
    if (v is null) { w.WriteNullValue (); return; }
    w.WriteStringValue (v.Name);
}
Defensive patterns

Strategy: try-catch

Try / catch

try { sourcesManager.ToJson (scope); }
catch (JsonException ex) when (ex.Message.Contains ("Error writing property with converter"))
{
    // ex.InnerException carries the converter's real exception
    Logging.Error ($"Write failed: {ex.InnerException?.Message}");
}

Prevention

When it happens

Trigger: Serializing a configuration property whose custom converter's Write throws — e.g. the converter cannot handle null, throws on an out-of-range enum, or fails on a value it wasn't designed for. Reached from any Write path (ConfigurationManager.ToJson, SourcesManager.ToStream, etc.).

Common situations: A converter assumes non-null but the property value is null; a converter written for an older schema encounters a new value; an enum converter hits an undefined member.

Related errors


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