tui-cs/Terminal.Gui · error · JsonException

{propertyType.FullName}: No source-generated JsonTypeInfo is

Error message

{propertyType.FullName}: No source-generated JsonTypeInfo is registered for this configuration property type.

What it means

Thrown in ScopeJsonConverter.DeserializePropertyValue (the Read path) when a configuration property's declared property type has no source-generated JsonTypeInfo in TuiSerializerContext. This is the deserialize-side counterpart of error 82: the reader has a property value to consume but the type was never registered for source generation, so reflection-free deserialization is impossible.

Source

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

        if (enumType.IsEnum)
        {
            if (reader.TokenType == JsonTokenType.String)
            {
                return Enum.Parse (enumType, reader.GetString ()!, true);
            }

            if (reader.TokenType == JsonTokenType.Null && nullableType is { })
            {
                return null;
            }
        }

        JsonTypeInfo? jsonTypeInfo = TuiSerializerContext.Instance.GetTypeInfo (propertyType);

        if (jsonTypeInfo is null)
        {
            throw new JsonException ($"{propertyType.FullName}: No source-generated JsonTypeInfo is registered for this configuration property type.");
        }

        return JsonSerializer.Deserialize (ref reader, jsonTypeInfo);
    }

    private static bool ShouldSkipNullPropertyValue (Type? propertyType, object? propertyValue)
    {
        if (propertyValue is { })
        {
            return false;
        }

        if (propertyType is null)
        {
            return false;
        }

        return propertyType.IsValueType && Nullable.GetUnderlyingType (propertyType) is null;

View on GitHub (pinned to 2e47b11478)

Solutions

  1. Register the property type with [JsonSerializable(typeof(...))] on the SourceGenerationContext partial class.
  2. If trimming is the cause, add a DynamicDependency or root the type with a rd.xml/DynamicDependency attribute, or disable trimming for that assembly.
  3. Remove the unregistered property from the config file so the reader never tries to deserialize it.

Example fix

// before - property type not registered
public static MyCustomType Thing { get; set; }

// after
// In SourceGenerationContext.cs:
[JsonSerializable (typeof (MyCustomType))]
internal partial class SourceGenerationContext : JsonSerializerContext { }
Defensive patterns

Strategy: validation

Validate before calling

// Before loading a config, ensure each property type is source-generated
foreach (ConfigProperty cp in scope.Values)
{
    Type? t = cp.PropertyInfo?.PropertyType;
    if (t is { } && SourceGenerationContext.Default.GetTypeInfo (t) is null)
        Logging.Warning ($"{t} has no JsonTypeInfo; reading it from JSON will throw.");
}

Type guard

static bool IsRegisteredForDeserialization (Type t) => SourceGenerationContext.Default.GetTypeInfo (t) is not null;

Try / catch

// SourcesManager already wraps this; set ThrowOnJsonErrors=false to log instead of throw
ConfigurationManager.ThrowOnJsonErrors = false;

Prevention

When it happens

Trigger: Loading a config JSON where a key maps to a ConfigProperty whose PropertyInfo.PropertyType is not in SourceGenerationContext — e.g. a property added to a fork without updating the source generator, or a type that was trimmed away. Reached from SourcesManager.Load -> ScopeJsonConverter.Read -> DeserializePropertyValue.

Common situations: Trimming/AOT removes the type metadata; adding a new config property type and forgetting [JsonSerializable]; renaming a type so the old source-gen registration no longer matches.

Related errors


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